{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "68580631",
   "metadata": {},
   "source": [
    "@题目1 手写汉字识别"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b8b3d12e",
   "metadata": {},
   "source": [
    "# 处理数据集"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "86c4bfa0",
   "metadata": {},
   "source": [
    "## 先读入训练集txt，制作映射表"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 91,
   "id": "f8a1be26",
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "tmp=[]\n",
    "with open('./data/HandWrite/HW_Chinese/train.txt','r') as f:\n",
    "    for lines in f:\n",
    "        if lines.startswith('\\n'):\n",
    "            continue\n",
    "        ib_idx=lines.index(' ')\n",
    "        s=lines[ib_idx:-1]\n",
    "        tmp.append(s[1:])\n",
    "sk=set()\n",
    "for i in tmp:\n",
    "    for c in i:  \n",
    "        sk.add(c)\n",
    "one_hot=list(sk)\n",
    "ss=''\n",
    "for i in one_hot:\n",
    "    ss+=i\n",
    "with open('./data/ss1.txt','w') as f:\n",
    "    f.write(ss)\n",
    "    f.write('\\n')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 91,
   "id": "53324352",
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "tmp=[]\n",
    "with open('./data/HandWrite/HW_Chinese/train.txt','r') as f:\n",
    "    for lines in f:\n",
    "        if lines.startswith('\\n'):\n",
    "            continue\n",
    "        ib_idx=lines.index(' ')\n",
    "        s=lines[ib_idx:-1]\n",
    "        tmp.append(s[1:])\n",
    "sk=set()\n",
    "for i in tmp:\n",
    "    for c in i:  \n",
    "        sk.add(c)\n",
    "one_hot=list(sk)\n",
    "ss=''\n",
    "for i in one_hot:\n",
    "    ss+=i\n",
    "with open('./data/ss1.txt','w') as f:\n",
    "    f.write(ss)\n",
    "    f.write('\\n')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 98,
   "id": "ca734a94",
   "metadata": {
    "collapsed": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['线处失守边缘同花',\n",
       " '业发车补贴两千余',\n",
       " '从年审计署公布的',\n",
       " '障和改善民生的头',\n",
       " '开了一个洞当他',\n",
       " '工作规格般为副',\n",
       " '的情况授予安监',\n",
       " '库房用绳索和抬',\n",
       " '区复赛刚刚在上邦',\n",
       " '数今日的走势来看',\n",
       " '成本线已经处于失',\n",
       " '束机制不健全企业',\n",
       " '下调煤炭价格以应',\n",
       " '瓶可乐然后再找可',\n",
       " '美国运至广州港不',\n",
       " '关单数据为出口企',\n",
       " '流中心的天然基',\n",
       " '中间人再通过中间',\n",
       " '百分点一年期贷',\n",
       " '内中间人经查王挺',\n",
       " '个改革开放基础',\n",
       " '带动东北振兴武',\n",
       " '的同事早已完成万',\n",
       " '并未同其合作我们',\n",
       " '实需要他认为大连',\n",
       " '低贷款利率却同时',\n",
       " '的是前期搭着高油',\n",
       " '展高科技产业山西',\n",
       " '大牌银行多赚元中',\n",
       " '和李力连男岁中国',\n",
       " '新晋商新形象新境',\n",
       " '成比例与西方国家',\n",
       " '说事故原因目前正',\n",
       " '效应可能存在不愿',\n",
       " '补偿尚未开启的可',\n",
       " '的爱好这包括其管',\n",
       " '特别是现代犯罪',\n",
       " '心国泰基金表示昨',\n",
       " '有的同事早已完成',\n",
       " '主管出口企业出口',\n",
       " '学医疗中心照顾',\n",
       " '谢罪赔偿等横幅高',\n",
       " '对这起指控他矢',\n",
       " '难耐寂寞与站街女',\n",
       " '救援人员在戈壁腹',\n",
       " '职各守其岗上述安',\n",
       " '走她就死给他看男',\n",
       " '家添利博时裕祥长',\n",
       " '美国创新力上升欧',\n",
       " '四架口气很大袁',\n",
       " '口和龙头立足大',\n",
       " '公司重大资产重组',\n",
       " '前瞻性进一步增',\n",
       " '相对高位杀跌力',\n",
       " '内政部长马尔万等',\n",
       " '站的二期工程包',\n",
       " '以上述价格收购',\n",
       " '可能很快出现因此',\n",
       " '人民一定会记',\n",
       " '足够的放水空间然',\n",
       " '这样设计主要是',\n",
       " '产法修正案征求意',\n",
       " '存状态的汇丰采',\n",
       " '后别忘了参加专业',\n",
       " '大队副大队长刘会',\n",
       " '上周进行预披露创',\n",
       " '知道爆出来了这么',\n",
       " '物试行启运港退',\n",
       " '大臣等名大臣被',\n",
       " '近实在拖不下去了',\n",
       " '库尔尼科娃与男友',\n",
       " '少有人在本次风灾',\n",
       " '习惯庞思索了几',\n",
       " '排和环境保护发挥',\n",
       " '实在的刚才很多问',\n",
       " '行初步判定结论如',\n",
       " '库存在码头仓房堆',\n",
       " '次可上浮至基准利',\n",
       " '识别系统可核对身',\n",
       " '堪入目的手机短信',\n",
       " '和送欢乐下基层活',\n",
       " '汉市市容环境卫生',\n",
       " '罪嫌疑人缴获案',\n",
       " '五世及罗密欧与朱',\n",
       " '批的省级文保单',\n",
       " '电记者有之希腊',\n",
       " '错绝不道歉但这',\n",
       " '亚的访问前往约旦',\n",
       " '意料月日一名衣衫',\n",
       " '踩雷叶檀央行降息',\n",
       " '两难格局新华网上',\n",
       " '处对内是海陆联运',\n",
       " '活的追求武汉也渐',\n",
       " '警通过千里追踪数',\n",
       " '乏神通广大者小张',\n",
       " '主也有基金公司表',\n",
       " '经同意扩大人道',\n",
       " '食品样品万个检查',\n",
       " '成立专门调查委员',\n",
       " '火近距离枪击和',\n",
       " '鉴别他们的价值当',\n",
       " '流动性信托模式',\n",
       " '会调查了差不多两',\n",
       " '司预计月的工作日',\n",
       " '员戴着空气呼吸器',\n",
       " '建高尔夫球场的通',\n",
       " '类产品如国联安双',\n",
       " '家级新区将获得财',\n",
       " '警告讯号并组织周',\n",
       " '乌恰县日晚间发生',\n",
       " '对此江苏丰县顺',\n",
       " '十年国家发展改革',\n",
       " '青年油画家以其创',\n",
       " '日下边落款是河',\n",
       " '显然有点撑不住前',\n",
       " '此事重庆市房管局',\n",
       " '吁行业协会科研',\n",
       " '新力近年来胶南持',\n",
       " '客平台仅提供信息',\n",
       " '年月日上海浦东国',\n",
       " '劳务派遣人员的单',\n",
       " '圈而在十分钟的文',\n",
       " '公共服务基础设施',\n",
       " '的左文隶今年岁是',\n",
       " '多次受到支撑此',\n",
       " '报讯记者韩旭昨',\n",
       " '的武器叙利亚当局',\n",
       " '家上市公司重大资',\n",
       " '有雷阵雨其余市县',\n",
       " '客网总经理助理',\n",
       " '同事度更年期看尽',\n",
       " '来的超额收益方',\n",
       " '上的谣言如何处理',\n",
       " '昌在致词时表示马',\n",
       " '有采取合理措施处',\n",
       " '是说需要炒股的话',\n",
       " '表示目前宏观经济',\n",
       " '理和使用有关的规',\n",
       " '批准建设新的高尔',\n",
       " '怪异得多有大幅上',\n",
       " '行抢食市场蛋糕的',\n",
       " '大雨发生滑坡造成',\n",
       " '校设置个志愿专业',\n",
       " '要为基础设施和地',\n",
       " '点本周还将有英国',\n",
       " '对方一刀捅',\n",
       " '死后逃之案件',\n",
       " '须悲观年月份全国',\n",
       " '中国雅虎侠客平台',\n",
       " '来的不良后果当然',\n",
       " '购物区欧美阿联酋',\n",
       " '赞阶梯电价实现富',\n",
       " '的国民新党副代表',\n",
       " '消费为债务人减负',\n",
       " '不少申请旁听者而',\n",
       " '析人士表示大连如',\n",
       " '会给房地产市场带',\n",
       " '忠德本报通讯员',\n",
       " '生更大地震的可能',\n",
       " '日消息近日中美执',\n",
       " '警告日本读卖新闻',\n",
       " '客户过得遥自在',\n",
       " '宜获得有条件通过',\n",
       " '选基金吧四年多里',\n",
       " '与基准利率的背离',\n",
       " '头大连港位居西北',\n",
       " '下一步对融',\n",
       " '并组织周围米直径',\n",
       " '清晰记得月日市场',\n",
       " '业才是开发商的利',\n",
       " '退税政策货物若',\n",
       " '企业社会责任意识',\n",
       " '其中一男子将手里',\n",
       " '广大城乡居民分享',\n",
       " '公司再与用工单位',\n",
       " '不变相对货币市场',\n",
       " '年期定期存款利率',\n",
       " '阿拉伯板块正从',\n",
       " '友也辞去了法国国',\n",
       " '利亚供应战斗直升',\n",
       " '短期内有非对称降',\n",
       " '迪车车主何先生宁',\n",
       " '能再让土地空闲',\n",
       " '的意见下简称意见',\n",
       " '定存利率税后加',\n",
       " '二是政策层面国际',\n",
       " '跌以及国际板点',\n",
       " '的手脚链锁青年中',\n",
       " '与我国保险行业发',\n",
       " '定自年月日起下调',\n",
       " '元等中国奶牛养殖',\n",
       " '京蓝色港湾置业有',\n",
       " '累华宝油气前十大',\n",
       " '布置进入收尾阶段',\n",
       " '前陈桔元砸开了房',\n",
       " '吨而秦皇岛大卡煤',\n",
       " '风险投资者要对自',\n",
       " '生图为自治区人民',\n",
       " '雅虎侠客平台仅提',\n",
       " '买到所以不少市民',\n",
       " '建起来业界人士指',\n",
       " '贷计划食品添加剂',\n",
       " '得负债率高效率低',\n",
       " '家后有人故意做了',\n",
       " '公司同时承诺在未',\n",
       " '差异的不均衡性已',\n",
       " '渐分离这两个新板',\n",
       " '媒体工作她们有些',\n",
       " '作人员向记者证实',\n",
       " '上午三菱劳工索',\n",
       " '就形成了扩张融资',\n",
       " '直升机俄罗斯外交',\n",
       " '梯内挥拳打伤女医',\n",
       " '利亚霍姆斯哈马',\n",
       " '涨幅预期值在之',\n",
       " '比亚和俄罗斯的廉',\n",
       " '其实际收益就更',\n",
       " '别市县可能出现左',\n",
       " '所犯下的犯罪事实',\n",
       " '担心随着成交量',\n",
       " '谓是砸锅卖铁拉存',\n",
       " '下游饮水造成威胁',\n",
       " '存款和完成业绩任',\n",
       " '偿负面新闻传播很',\n",
       " '收益都在以上最高',\n",
       " '诉书内容情人节当',\n",
       " '门并进行现场文物',\n",
       " '期存款利息不降反',\n",
       " '道明天凌晨两场欧',\n",
       " '起捡钱分钱诈骗案',\n",
       " '析看一看艺',\n",
       " '此前的长期定存利',\n",
       " '及时解决医患纠纷',\n",
       " '内容均由上网用户',\n",
       " '全部被上面拿走了',\n",
       " '书面回复可乐瓶里',\n",
       " '暴起咬人全过',\n",
       " '法犯罪行为要果断',\n",
       " '在水和鹿肉中发现',\n",
       " '分的两支球队分别',\n",
       " '地方各级政府国务',\n",
       " '秀明星耶德古迪和',\n",
       " '仍将保持增长但增',\n",
       " '正是各行纷纷抬高',\n",
       " '与男友驾游艇出游',\n",
       " '及生命伤者中人中',\n",
       " '长向记者介绍他',\n",
       " '节能减排环境保',\n",
       " '般为副部级今年两',\n",
       " '设和运营为主营业',\n",
       " '停水停电停气渠城',\n",
       " '股建设银行万股同',\n",
       " '财有研究显示良好',\n",
       " '多名类似王挺的中',\n",
       " '害公众健康和安全',\n",
       " '梁先生拒绝其后梁',\n",
       " '元改扩建处农村文',\n",
       " '伯国家在土耳其伊',\n",
       " '初步判定结论如下',\n",
       " '板的北京英博电气',\n",
       " '控制与预防中心提',\n",
       " '台从而将潜在的中',\n",
       " '少年无钱治疗含泪',\n",
       " '档对困难群体给予',\n",
       " '另一同伙则在',\n",
       " '叙利亚主要反对组',\n",
       " '地发挥窗口作用国',\n",
       " '工行中行建行和汇',\n",
       " '局局长刘安成因为',\n",
       " '坡上有响声她立刻',\n",
       " '划和审批相关特殊',\n",
       " '个区域经社委员会',\n",
       " '捕民警分组前往淄',\n",
       " '难以见底但是通',\n",
       " '其职各守其岗上述',\n",
       " '高回报的项目可贷',\n",
       " '亿的艺术品成立于',\n",
       " '违法建设整治过程',\n",
       " '金凤镇的上邦国际',\n",
       " '外部宽松所带来的',\n",
       " '因成为公牺牲官方',\n",
       " '人都是无辜的路人',\n",
       " '为亿元万元亿元',\n",
       " '板方面南京宝色丹',\n",
       " '荣景象有业内人士',\n",
       " '月日下午时分许西',\n",
       " '对唱女生表现出',\n",
       " '困难群体给予定',\n",
       " '的石膏板产能布局',\n",
       " '资产关联交易方',\n",
       " '阶梯电价评述之',\n",
       " '川月日消息记者胡',\n",
       " '两层楼的库房大门',\n",
       " '中山站至冰断面',\n",
       " '短缺困境自从年初',\n",
       " '命并与在叙利亚国',\n",
       " '房贷月供减少元有',\n",
       " '已超过万人约万人',\n",
       " '的可乐朋友欲拿元',\n",
       " '企业先支付预付',\n",
       " '金等款项上述标的',\n",
       " '对驾驶者和其他',\n",
       " '电量增长有限南方',\n",
       " '收益率的可能性较',\n",
       " '不能在网络渠道购',\n",
       " '山群岛新区之后第',\n",
       " '医疗中心照顾名',\n",
       " '销人员有任务今年',\n",
       " '的各种沸沸扬扬大',\n",
       " '在与美国贸易商签',\n",
       " '意愿共同创建没有',\n",
       " '城市反哺农村体现',\n",
       " '一路走高中国海',\n",
       " '单位进行了量化评',\n",
       " '关人士表示从东北',\n",
       " '这一切程',\n",
       " '山西人从商历史悠',\n",
       " '就穿着白色比基尼',\n",
       " '以配合征求意见稿',\n",
       " '的宽松政策会对市',\n",
       " '负责安保的军官说',\n",
       " '邦文投资承担连带',\n",
       " '的现代化转型仅',\n",
       " '宣布日电价缓涨',\n",
       " '幅上升进口和出',\n",
       " '流露当被公诉人质',\n",
       " '股份有限公司在山',\n",
       " '使资金流出银行体',\n",
       " '规划部门是依据什',\n",
       " '些价值股也有定',\n",
       " '检部门的检验满',\n",
       " '居民阶梯电价听证',\n",
       " '痛哭北京时间今天',\n",
       " '供中国雅虎提示您',\n",
       " '重组中股票异常',\n",
       " '完成了整改其他问',\n",
       " '死因成为公牺牲官',\n",
       " '家属和陪护人员他',\n",
       " '投资方向运作模式',\n",
       " '响从上证指数今',\n",
       " '海关缉私局成立联',\n",
       " '经济与政策的来回',\n",
       " '份查处的每日经济',\n",
       " '但警方称已掌握嫌',\n",
       " '违反本社区规定而',\n",
       " '对于这样种种的矛',\n",
       " '装调试污水处理等',\n",
       " '国务院食安委的统',\n",
       " '的火电企业实行脱',\n",
       " '势是德国和丹麦分',\n",
       " '实施本报月日讯通',\n",
       " '续出现你认为基',\n",
       " '亡月日台湾考试院',\n",
       " '午梁先生将与可口',\n",
       " '行通过美牛案证所',\n",
       " '和保险资金启动增',\n",
       " '根据情况征集考生',\n",
       " '会立即将其遣返不',\n",
       " '召回事件日前日本',\n",
       " '攻基本上我国的煤',\n",
       " '市场利率较高的情',\n",
       " '日四大行已经对汇',\n",
       " '实习并于月日随公',\n",
       " '一中院门口始',\n",
       " '手绳之以法我们必',\n",
       " '对产生的后果负责',\n",
       " '一季度共有艺',\n",
       " '会太强按现行规定',\n",
       " '随后并没有进一',\n",
       " '分级管理工作根据',\n",
       " '股发行询价过程中',\n",
       " '可再生能源电价政',\n",
       " '上海洋山保税港区',\n",
       " '注焦点胡拉镇事件',\n",
       " '事务部贸易发展会',\n",
       " '男的还真敢死啊',\n",
       " '者硬币的价值只能',\n",
       " '色气体易燃易爆有',\n",
       " '的方式设置用钱的',\n",
       " '放根据招商证券',\n",
       " '相对薄弱的人群',\n",
       " '存款成为银行争夺',\n",
       " '市单价地王纪录该',\n",
       " '源紧缺以及由能源',\n",
       " '及时进行信息披露',\n",
       " '回的景象形成了鲜',\n",
       " '式进行扶持要坚持',\n",
       " '银行理财师私下',\n",
       " '增长率更明显低于',\n",
       " '统一规划',\n",
       " '域金融垄断程度高',\n",
       " '倍这不是天方夜谭',\n",
       " '达目的绝不罢休三',\n",
       " '型工具为主进行调',\n",
       " '屏幕上准时出现了',\n",
       " '降息深受大宗商品',\n",
       " '伤害而丧生其中包',\n",
       " '职年月日马尔代',\n",
       " '题银行圈钱发展模',\n",
       " '策因为刚需更加务',\n",
       " '为张绍刚存在自卑',\n",
       " '划向叙利亚万人提',\n",
       " '业创出个月以来的',\n",
       " '姐告诉记者其实',\n",
       " '中主要是省级平台',\n",
       " '东曲阜孔林附近女',\n",
       " '心师傅故意触碰胸',\n",
       " '们看到了攻打叙利',\n",
       " '定和等级公示宁夏',\n",
       " '部门依据职能分工',\n",
       " '用餐配送单位中央',\n",
       " '将非洲板块分为',\n",
       " '住了记者隔着教堂',\n",
       " '多市长罗布福特在',\n",
       " '过渡应该包括叙利',\n",
       " '日重周期行业表',\n",
       " '选举得以举行法国',\n",
       " '会正在加强与各',\n",
       " '沙河南岸风景',\n",
       " '明进行反驳指出',\n",
       " '图书馆等公共文化',\n",
       " '士表示大连设立国',\n",
       " '银行首套房贷利率',\n",
       " '大量的清洗工作',\n",
       " '人和爱国华侨的支',\n",
       " '至兴业银行首席经',\n",
       " '司和险资的持股成',\n",
       " '务业金融业石油开',\n",
       " '解便拿着手中的业',\n",
       " '月日上海老相机制',\n",
       " '是要坚持与国际',\n",
       " '渐近也标志着在',\n",
       " '企业发车补贴两千',\n",
       " '作为置出资产与中',\n",
       " '医院保持高度警戒',\n",
       " '台仅提供信息存',\n",
       " '正义的原则发改委',\n",
       " '居住需求外最主要',\n",
       " '国民警卫队参谋军',\n",
       " '案组迅速开展案件',\n",
       " '锣鼓等文化设施',\n",
       " '谋去年一场声势',\n",
       " '基本用电需求发挥',\n",
       " '精选基金吧混合基',\n",
       " '进党中央如何协助',\n",
       " '挑选难度在加大',\n",
       " '责任扎实推进量化',\n",
       " '维持经济增长不得',\n",
       " '效申购金额为亿元',\n",
       " '申报企业基本信息',\n",
       " '出探索建立到完善',\n",
       " '举行月日至日被确',\n",
       " '在大连设立国家级',\n",
       " '一开始上海',\n",
       " '物局列为河南省第',\n",
       " '人士认为随着货币',\n",
       " '唱成了红着但这恰',\n",
       " '质询不过由于陈冲',\n",
       " '路运输适用启运港',\n",
       " '英拉慰问月日在',\n",
       " '起咬人全过程中国',\n",
       " '组组当中两支传统',\n",
       " '全部货物进入离境',\n",
       " '径有专家表示由于',\n",
       " '基本促公平的制度',\n",
       " '耕种并垫付租金并',\n",
       " '者介绍他们之所以',\n",
       " '竟然允许开发商在',\n",
       " '太平洋面向世界的',\n",
       " '重大食品安全事故',\n",
       " '丰县顺河镇政府负',\n",
       " '能分工对使用政府',\n",
       " '索转变发展方式和',\n",
       " '些产品也可达到',\n",
       " '导致行政部门首长',\n",
       " '的不均衡性已经',\n",
       " '太仓一家宾馆还',\n",
       " '长城去年重新审核',\n",
       " '相关法律规定部',\n",
       " '计划对李旭利案的',\n",
       " '举得以举行法国还',\n",
       " '头整治的对象包',\n",
       " '利率走低经济回暖',\n",
       " '字里面挑刺然后',\n",
       " '关法律规定部分内',\n",
       " '汤灿被判年消息',\n",
       " '到这瓶可乐之后辗',\n",
       " '利亚供应直升机俄',\n",
       " '骨的变化袁纯清说',\n",
       " '公布一些构',\n",
       " '外走富玲说当时',\n",
       " '连分析人士表示',\n",
       " '极性减退甚至有港',\n",
       " '连经济和支柱产',\n",
       " '处于下行通道外围',\n",
       " '就被一抢而空',\n",
       " '最早出现的艺术品',\n",
       " '救护队的多名专业',\n",
       " '表示目前银行销售',\n",
       " '火力的武装分子目',\n",
       " '几厘米的水果刀',\n",
       " '地总建筑规模超',\n",
       " '水平保险市场发育',\n",
       " '故障停车图为发生',\n",
       " '捷的海上门户大连',\n",
       " '加高职单考单招的',\n",
       " '资成本刺激企业再',\n",
       " '存利率竟低至五年',\n",
       " '文通讯员陈佩云',\n",
       " '型文化广场加强市',\n",
       " '请点这里查看家中',\n",
       " '说别争了两期国债',\n",
       " '夺战三年定存利率',\n",
       " '问的水准层次不齐',\n",
       " '全宣传周活动由国',\n",
       " '而形成外部监管内',\n",
       " '证的小产权房全部',\n",
       " '关于居民阶梯电价',\n",
       " '息来源拉夫罗夫日',\n",
       " '权责一致的原',\n",
       " '了现在可谓是砸锅',\n",
       " '现场的警察和医护',\n",
       " '看清条款北新建材',\n",
       " '子的成长阶段而不',\n",
       " '经济体降息深受大',\n",
       " '大肠杆菌州扩散名',\n",
       " '的核心是法律和',\n",
       " '深感摸不着头脑长',\n",
       " '成为全国利率最优',\n",
       " '华夏银行的发行量',\n",
       " '刚才很多问题实际',\n",
       " '实际约定收益在之',\n",
       " '袭击万人受灾山东',\n",
       " '时规定申请成为常',\n",
       " '辆车牌号为赣的长',\n",
       " '叙利亚问题举行了',\n",
       " '果没有赚钱效应可',\n",
       " '加明显四大行目前',\n",
       " '并购重组委审核公',\n",
       " '监张大伟认为在',\n",
       " '娘打麻将不入洞房',\n",
       " '融机构人民币存贷',\n",
       " '实施意见详细规定',\n",
       " '显示去年美国大豆',\n",
       " '大连新市区位于东',\n",
       " '人提供援助月份',\n",
       " '重让国内煤炭企',\n",
       " '础资产的选择要兼',\n",
       " '媒体传出荷兰队出',\n",
       " '公司讲数梁先生问',\n",
       " '得再凶张绍刚也',\n",
       " '生山体滑塌事故月',\n",
       " '海关提供税务机关',\n",
       " '情后愿意以元的价',\n",
       " '下跌带来的净值损',\n",
       " '巴瘤于月日至月日',\n",
       " '食药监局工作部署',\n",
       " '出了规定种植环节',\n",
       " '刚的问题在于俯视',\n",
       " '约的比例但高于发',\n",
       " '项目价格上涨月平',\n",
       " '第远落后于日韩中',\n",
       " '闻中国雅虎侠客平',\n",
       " '公募基金领域年以',\n",
       " '暴露在风险之下',\n",
       " '佐治亚州例路易斯',\n",
       " '的质疑并不算大但',\n",
       " '治的对象包括年关',\n",
       " '目的申购新股的中',\n",
       " '南市珠海街道办事',\n",
       " '发现小强受伤昏',\n",
       " '里头但是一个',\n",
       " '枪商场内随后出',\n",
       " '逮捕了该案主犯现',\n",
       " '立足已有功能区设',\n",
       " '就是典型案例市场',\n",
       " '子上的内容就签了',\n",
       " '请折农业银行手',\n",
       " '华远地产股份有限',\n",
       " '查犯罪嫌疑人陈',\n",
       " '惯庞思索了几秒',\n",
       " '加强安全生产管',\n",
       " '主义援助万叙利',\n",
       " '门审批文物的保护',\n",
       " '场兴起时间不长部',\n",
       " '质饲料对华出口而',\n",
       " '优势并拥有相对需',\n",
       " '价值都一样认为',\n",
       " '的监控系统不但可',\n",
       " '为约定收益的支',\n",
       " '此在公安部和海关',\n",
       " '地方新疆地震局乌',\n",
       " '董事会于年月日审',\n",
       " '品安全需要社会各',\n",
       " '因非法侵入他人住',\n",
       " '银行的发行量居前',\n",
       " '力的武装分子目标',\n",
       " '委员会第一委员',\n",
       " '武献华提出了关于',\n",
       " '年期定存利率分别',\n",
       " '强烟台市政府日前',\n",
       " '专业高考进程月日',\n",
       " '相关院校信息专科',\n",
       " '对比可以看到投资',\n",
       " '帆布和警戒线围了',\n",
       " '是余彭年所拥有的',\n",
       " '每人吃了片被人发',\n",
       " '的理财习惯年龄金',\n",
       " '虎提示您尊重权利',\n",
       " '变国内煤炭的整体',\n",
       " '管理生态调查港',\n",
       " '上救市贷款基准利',\n",
       " '一定优势并',\n",
       " '微博称为宗盘',\n",
       " '放缓趋势上周仅',\n",
       " '业务实施细则征求',\n",
       " '中山西临汾仍然被',\n",
       " '经济在市场中我们',\n",
       " '作者余乐来源羊城',\n",
       " '起公诉后改变管辖',\n",
       " '安排国际金融组织',\n",
       " '付租金并将通过法',\n",
       " '听的人数达百余人',\n",
       " '证明三启运港退',\n",
       " '索行政区与功能区',\n",
       " '考试院长关中独生',\n",
       " '公布专科分数线月',\n",
       " '门附近拥堵的车',\n",
       " '昨日向多家有大批',\n",
       " '利率市场仅是探索',\n",
       " '普或许换位月日俄',\n",
       " '而分的如果再赢就',\n",
       " '线也在博物馆内重',\n",
       " '球迷来说今天晚上',\n",
       " '资讯成品油分析师',\n",
       " '放松的力度加大市',\n",
       " '升值为投资者带来',\n",
       " '套设施部分物业',\n",
       " '台贷计下降个基点',\n",
       " '强烈虽然据说输',\n",
       " '示从目前的银行信',\n",
       " '预叙利亚反对派',\n",
       " '上调出租车燃油附',\n",
       " '产品母基金投资类',\n",
       " '是用于国债政策性',\n",
       " '迅原唱的因为爱',\n",
       " '过平机会控告雇主',\n",
       " '落实国务院关于鼓',\n",
       " '北是我国面向东',\n",
       " '峻的国际经济环',\n",
       " '县人且该团伙人员',\n",
       " '发现乌木值百万当',\n",
       " '通知未予显示请点',\n",
       " '防阵雨图一位',\n",
       " '一体即将于',\n",
       " '年底或明年初进行',\n",
       " '行政负责人施政',\n",
       " '者的推荐工作建立',\n",
       " '法律规定部分内容',\n",
       " '月份全国居民消费',\n",
       " '未接电话过了几天',\n",
       " '别所有进入航天城',\n",
       " '鹏华丰泽债基基',\n",
       " '要向警方表达我的',\n",
       " '上报了额度申请但',\n",
       " '期的投资目前最受',\n",
       " '续第二个月降息累',\n",
       " '直批评医疗制度抨',\n",
       " '常生活渐行渐近也',\n",
       " '蚀作用最新朝鲜生',\n",
       " '行政部门首长提出',\n",
       " '荐类询价对象推荐',\n",
       " '少申请旁听者而实',\n",
       " '网络上疯传的则',\n",
       " '过仍维持在低位贸',\n",
       " '行银行员工倒苦',\n",
       " '规模恐慌加拿大',\n",
       " '不是报一个',\n",
       " '又一重要举措',\n",
       " '垣市长如此未雨绸',\n",
       " '内人士分析去年以',\n",
       " '外是东北亚地区国',\n",
       " '除去加大宣传力度',\n",
       " '即时解雇事主透过',\n",
       " '本论坛的主旨本社',\n",
       " '评级机构标准普',\n",
       " '预计降价幅度不会',\n",
       " '烟台市政府日前出',\n",
       " '非法枪爆物品活动',\n",
       " '结构比例符合中央',\n",
       " '金正恩为少年团代',\n",
       " '摄像头扫描读卡',\n",
       " '男子为逃脱遂将胡',\n",
       " '示月日上述四港煤',\n",
       " '有关在大连设立国',\n",
       " '记者目前大部分房',\n",
       " '咨询在研究报告中',\n",
       " '害公众健康和安',\n",
       " '思所想有问题的认',\n",
       " '业高考进程月日日',\n",
       " '时常吵架我就是想',\n",
       " '部的装布置进入',\n",
       " '同比涨幅进一',\n",
       " '现实需要他认为',\n",
       " '等待判决他失去自',\n",
       " '方向改革我国出租',\n",
       " '局长刘绍武介绍这',\n",
       " '见面平时各过各的',\n",
       " '代表大会代表资格',\n",
       " '方彻查枪源美方执',\n",
       " '负责审核二主要',\n",
       " '的岛屿管理生态调',\n",
       " '选人初步人选的',\n",
       " '装甲车卷起尘土前',\n",
       " '染上乙肝向生产商',\n",
       " '网月日消息据台湾',\n",
       " '基础管理建立长效',\n",
       " '依旧取得了很大成',\n",
       " '一个两难格局为',\n",
       " '在江苏扬州辽宁营',\n",
       " '次检出不合格进出',\n",
       " '元加上外汇占款可',\n",
       " '促公平这一',\n",
       " '开发的昌建外滩高',\n",
       " '点他指出不少售房',\n",
       " '中方渔政船曾次进',\n",
       " '就更多而根据标普',\n",
       " '第一枪平安银',\n",
       " '仓房堆积如山库存',\n",
       " '求多项数据料维持',\n",
       " '一枢纽的先行区',\n",
       " '下称雅盈堂实际',\n",
       " '行央行加大货币紧',\n",
       " '仅有几十万元的普',\n",
       " '的基本框架原则',\n",
       " '然发现高大的架桥',\n",
       " '渣打银行就要多得',\n",
       " '店会所等商品房和',\n",
       " '营企业的以上这',\n",
       " '无论是海外还是国',\n",
       " '日环食中国雅虎侠',\n",
       " '周末商场内至少聚',\n",
       " '注意的是分级债基',\n",
       " '用了约分钟你来晚',\n",
       " '发生级地震新疆',\n",
       " '不执行安全生产监',\n",
       " '运到广州港为元吨',\n",
       " '通宵麻将哪知第二',\n",
       " '卫生厅要求医疗机',\n",
       " '知未予显示请点这',\n",
       " '辉偿付能力监管体',\n",
       " '玻璃瓶可回收经清',\n",
       " '投资者望而却步征',\n",
       " '发现男子今年岁孩',\n",
       " '和使用中的违法行',\n",
       " '真地处理工作场所',\n",
       " '市将公共文化设施',\n",
       " '将食品安全工作列',\n",
       " '时指出我国民营企',\n",
       " '您尊重权利人之权',\n",
       " '叙利亚供应战斗直',\n",
       " '护和保障食品安全',\n",
       " '一步完善其制度',\n",
       " '有效报价或申购要',\n",
       " '还会做做鬼脸与父',\n",
       " '批的省级文保单位',\n",
       " '宣布幕剧院保存',\n",
       " '让议事再次陷入',\n",
       " '小产权房开绿灯无',\n",
       " '设厅评为拆迁管理',\n",
       " '房价的预期他还表',\n",
       " '友在迈阿密海边度',\n",
       " '统不但可随时与',\n",
       " '出这起拆迁的实',\n",
       " '我尊严劳工历史不',\n",
       " '行政院仍一意孤',\n",
       " '的新阶段迫切需要',\n",
       " '评价意见看中央企',\n",
       " '挑刺然后喝批判',\n",
       " '消息将湖南推向了',\n",
       " '去了法国国际广播',\n",
       " '条款北新建材及其',\n",
       " '民出门不妨带备雨',\n",
       " '家庭协会副秘书长',\n",
       " '府节省了万元的支',\n",
       " '是发改委今日文章',\n",
       " '钓鱼岛争端不断日',\n",
       " '重时不时地打土豪',\n",
       " '大众日报金正恩',\n",
       " '来有代表性的艺术',\n",
       " '善与市场经济相适',\n",
       " '内容在新股发行询',\n",
       " '行同比涨幅较上月',\n",
       " '的女司机迟到导',\n",
       " '旧金山月日电记者',\n",
       " '查看活跃在全球',\n",
       " '前还没有足够的事',\n",
       " '基发展迅速目前已',\n",
       " '品非法添加和滥',\n",
       " '家的不是银行的存',\n",
       " '司董事长黄宇杰由',\n",
       " '际合作的不断深化',\n",
       " '帮他请关注逃命到',\n",
       " '济与政策的来回博',\n",
       " '工地方已加紧抢',\n",
       " '海游玩时候的镜头',\n",
       " '业金融业石油开',\n",
       " '样这是为了你好而',\n",
       " '里查看法国第女',\n",
       " '时还需经党的第十',\n",
       " '收益率的可能性较',\n",
       " '的硬性要求银行必',\n",
       " '她一拳就跑医',\n",
       " '值股和成长股基本',\n",
       " '案在中国抓获犯罪',\n",
       " '个基点至这是该行',\n",
       " '升至历史高位从',\n",
       " '台公司贷款被明确',\n",
       " '人之权利根据相',\n",
       " '中行招行汇丰等大',\n",
       " '案不管是美牛或证',\n",
       " '卫生厅呼吁一',\n",
       " '制所以一般情下',\n",
       " '之权利根据相关',\n",
       " '着手中的业务单前',\n",
       " '钓鱼岛岛但被东京',\n",
       " '人对这起指控他',\n",
       " '振精神做时代的新',\n",
       " '万存款变保单退回',\n",
       " '这是为了你好而自',\n",
       " '太温情了孩子望着',\n",
       " '下来能挣万多元在',\n",
       " '行为代表的多家股',\n",
       " '霜袋里再拧紧盖子',\n",
       " '手与记者相握这是',\n",
       " '建筑物安全应立',\n",
       " '国内以及邻国迫切',\n",
       " '下同时申购单新',\n",
       " '况也很不乐观今年',\n",
       " '启运地口岸为青岛',\n",
       " '由于每个孩子的性',\n",
       " '林信托发行了款',\n",
       " '务总局研究制定四',\n",
       " '放眼东北亚随着国',\n",
       " '不多于名个人投资',\n",
       " '回信托份额增加了',\n",
       " '市场环境下很难说',\n",
       " '安邦咨询研究员从',\n",
       " '集开放期据统计在',\n",
       " '债但需谨慎考量风',\n",
       " '清楚上邦高尔夫球',\n",
       " '观的背景下反周期',\n",
       " '元的存款到期取钱',\n",
       " '的放映权古迪指示',\n",
       " '物价回落中金公司',\n",
       " '营销费用就会打折',\n",
       " '地震发生后新疆地',\n",
       " '门口前等候你已经',\n",
       " '经中国证监会并购',\n",
       " '动物价回落中金公',\n",
       " '融资担保和跟进投',\n",
       " '年所发生的新的经',\n",
       " '中途不能取回想取',\n",
       " '另一位护士',\n",
       " '困难群众基本生活',\n",
       " '气渠城滨河路龙溪',\n",
       " '吸引了超过亿元资',\n",
       " '影新京报记者郭铁',\n",
       " '以及其他风险较低',\n",
       " '加大责任追究力度',\n",
       " '西北太平洋中枢是',\n",
       " '书画作品雅昌艺术',\n",
       " '不同通过不同的亲',\n",
       " '至有港口出现空泊',\n",
       " '孩子看和讲有关购',\n",
       " '部联赛南方区复赛',\n",
       " '有的廊坊开发区新',\n",
       " '次受到支撑此次',\n",
       " '牌吸引消费者购买',\n",
       " '连平微博表示当前',\n",
       " '的情况尤为严重',\n",
       " '肝向生产商索赔万',\n",
       " '而行月日华润银行',\n",
       " '根弯曲的吸管这瓶',\n",
       " '里公共文化服务圈',\n",
       " '官网上回应了日前',\n",
       " '连设立国家级新',\n",
       " '车的前部凹进的车',\n",
       " '空间服务其内容均',\n",
       " '触犯中华人民共和',\n",
       " '安全监管力度努力',\n",
       " '国的失业率出现反',\n",
       " '引导积极探索开创',\n",
       " '货币紧缩力度导致',\n",
       " '重创股指一',\n",
       " '即将于近期开工',\n",
       " '土在前行车内三名',\n",
       " '企业将乐于把新增',\n",
       " '党将会强烈反应今',\n",
       " '直径范围内的上',\n",
       " '了全面落实他于今',\n",
       " '俄罗斯党代表大会',\n",
       " '法部门联手成功破',\n",
       " '明确了评定程序公',\n",
       " '的活期存款利率均',\n",
       " '示分级债基上涨',\n",
       " '假话不是说我有双',\n",
       " '由贸易区先行区的',\n",
       " '感染这种病菌这些',\n",
       " '个人投资者望而却',\n",
       " '队内和葡萄牙队',\n",
       " '件万起重新审核并',\n",
       " '医院保持高度警戒',\n",
       " '野党要求先为证所',\n",
       " '虎提示您尊重权利',\n",
       " '房需求的平稳释放',\n",
       " '供万个食品包裹月',\n",
       " '收到短信通知报考',\n",
       " '度避免由于各类关',\n",
       " '疑人缴获作案车',\n",
       " '铁娘子麦卡利斯年',\n",
       " '分析表明各国央行',\n",
       " '这种思想碰撞达到',\n",
       " '金公司增持四大行',\n",
       " '络进行犯罪交易隐',\n",
       " '能多达人其中理',\n",
       " '务院食安委的统',\n",
       " '党前主席蔡英文桃',\n",
       " '利根据相关法律',\n",
       " '可能是保管不当造',\n",
       " '至符合市场预期这',\n",
       " '突还会长期地存在',\n",
       " '移动的大肥皂装',\n",
       " '日向每日经济新闻',\n",
       " '方称已掌握嫌疑人',\n",
       " '推动份额的表现鹏',\n",
       " '银行理财产品销售',\n",
       " '莎士比亚剧院遗址',\n",
       " '孩子学习理财儿',\n",
       " '楼下负责放风随后',\n",
       " '试需要提醒考生的',\n",
       " '拿大个省份经营业',\n",
       " '同时按持股比例支',\n",
       " '限用农药和有毒有',\n",
       " '的装甲车代号一',\n",
       " '还是会继续回落伟',\n",
       " '专题讨论比如页',\n",
       " '国民党下周将强行',\n",
       " '油附加费其中北京',\n",
       " '一侧倒下时个',\n",
       " '个中心舞台外还建',\n",
       " '天自己却加仓的经',\n",
       " '次假冒警察逼迫被',\n",
       " '组网上民意汹汹',\n",
       " '案被警方破获中广',\n",
       " '上戴面纱她希望来',\n",
       " '量价齐升庞说在为',\n",
       " '赛刚刚在此落幕去',\n",
       " '交易方案获得中国',\n",
       " '个检查食品生产单',\n",
       " '权利人之权利根据',\n",
       " '线月日月日专科提',\n",
       " '季度的高位降至左',\n",
       " '的内容就签了名字',\n",
       " '二主要流程出口企',\n",
       " '面溃败甚至远低于',\n",
       " '各家银行发行的组',\n",
       " '没有个人利益的驱',\n",
       " '的核心是法律和',\n",
       " '监督量化分级管理',\n",
       " '面向东北亚开合',\n",
       " '亿元计划主要为大',\n",
       " '激动开始谩骂侮辱',\n",
       " '胡师傅随后被送',\n",
       " '有工作人员介绍但',\n",
       " '证券公司下发了首',\n",
       " '结目前国内外煤价',\n",
       " '报道法国新任总统',\n",
       " '监会并购重组委审',\n",
       " '年月日调查逾十月',\n",
       " '涉嫌贪污更改为滥',\n",
       " '没想到他说着说着',\n",
       " '果就震荡所以绝对',\n",
       " '坚持市场化运作通',\n",
       " '主义援助走婚族悄',\n",
       " '调查发现目前各家',\n",
       " '监部门作出的停产',\n",
       " '药残留中央厨房卫',\n",
       " '及相关材料到主管',\n",
       " '据本周陆续公布',\n",
       " '难的事情因为它既',\n",
       " '妻子今年月在上海',\n",
       " '华社记者刘雪据新',\n",
       " '业课考试时间有',\n",
       " '从目前市场成交结',\n",
       " '多少定义添加剂的',\n",
       " '是时候我只是她',\n",
       " '的视角去寻找投资',\n",
       " '吗民警立刻赶到现',\n",
       " '干来源中国新闻网',\n",
       " ...]"
      ]
     },
     "execution_count": 98,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tmp #预览训练集标签"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "c14491f9",
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "with open('./data/ss1.txt','r') as f:\n",
    "    one_hot=f.readline()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "e34ebf40",
   "metadata": {},
   "outputs": [],
   "source": [
    "with open('./data/ss1.txt','w') as f:\n",
    "    f.write(one_hot)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "579c6ad9",
   "metadata": {
    "collapsed": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'底呈奇申月究直遗邱康另情翁避普熊沟鲍此扶捏没何播矛生详阶隙辨拟山渠辈闸哭盛泪块拍惋建鉴干代凤怪结迫椎棚彭垣澳赖抬画肉动照类栋泉截开浓皆尖板郭植某筹木桃呼抄置培悦吹滚吐磋圈凌夺场笼们挣拨献穷留衍构驳坡孤众衰筑欲沙综钻担瑶妻报遥辩壮扛城斩米妮教肝曝训抵车易遣惊滥如范消哥亢酬休蔬冤独打凶忠手瞻被评女传亿内币汇哗溃侯看研碌充版剂拉摩试孜皮晴搬僵轨堵即义往羽戒思逼朝铭赞鹏筒十纳胡薪赂言狙碗功跌编装猛收酿悬宝涛域册源少角罗劳航尺光位恶首制婿浪弥歉增弹领昭袋柜起抓陈束凳拧邮忙摊佐刚减硬进漳淘里端毒虽线猎催无剧序空粤霉绪索澄份声宿展宫北占规锦管吧擦岸顾压轻贵怀键拾快平峻桂纸威虑左逊妙灌临希惑它霍势侦疆贺侠京印霜厨初屿备冰液于朗撤方害案哺脸书兑分舍锁视茨千游辐桶便授核辛誉粹简青怒疑阜烈慈悔峰忧司亡侧持齐延死绝挖函士谩八驼履几终牌熟拓时狠坍衔津墩掀支造嗽拆达命桥厘屡衅劝贴维喜陶现油棺龙冉敲晰夷助林阳借堂境堆上地配骤个良适电骂价味循翼存胆灰乏条潮深词斑酒贝隔旗冀音删替件睁影王储致家旧座顿泽企盾摘冻及歪毁考称缮昨朴治庆经仓违恢寻既西李弗敛滩盲柴停史煮喉蹲到誓形勇谅悍爱帮繁好网钓垄苦校按撼箭河贿仙议恰牵职裸鱼谴乌侵迹难殷土了谣搜季么曲为胸剖颜扩亦购膨民换川缺著彰晨吓肩限莲部络触店包眼蹈护且幕技卫掉文斤葛惟凭带丈硝袭钞惨贷蛇慧袖嘲火中挑边摆纵那弱户策荡变闽固脂薛县未亲耳脱横冲揽竞岳牲亥昆标涌馆贸恋则融骨珠灼龄由始铃泥波泊些鲜瞧退善实小华艾捕因狼风太硫甚株朱滞陆怕恤比撞州指作乙攻肤喝湘偏低刺郡浴腹韦蹭枝咳址曾托四苏图参释廷排病厉坞卑划邵测请趴酱惯牛竟德伸姓梁概届满恩壳甲跪朋菌珍同熔多兄庚跨疼霓疯胁防又吊门冒乳靠税谨坦付修惜柔尘暂元双盟桌讶洋惩峡以亚敢蒋夹目奥帖片景更并滨孔呕抽举侨还姑郸莫象罕盈丛绕塞涉谁享扎重辉渺井答信吨悲据檀待监艇裂荣突介汕妨窗射精涂寿溪见豪室梨霞卢师狱碍毕球堡沂绩徐偷穿坐棒樊数斌吻缴寨色填等战式集缠粉雅贪辖挡神服浩奶社像允余拳挪饱布欧热屏廖导坛望做疲坏连立工卡床慢勿险拦居科邢爹琴裕劣斜臭默卜野缅理炒戏离化从取吉洗界肥聚掺毗央型归约而券守章颇庞阴楼秃墨度敏坠弟却回择丁选探批搏频抱呢晚员添尤翔量骄差拔水谋驱踪裤这鸟提夏相溯盆荒异越墙慰识辣夕认张渝道胀绑货果倾宣徽出糕官诈摸牧统侮躺政透援麦承具富馈孟逾然真矿匪焉摇群晓匿遭武孕市秽忘随焕派童求品啤句帝磺倍是骗路诚唯邻钱历刷母明姆整彻仔哑俱断泛花府尊甜炼宇雪街层淋杠放彦疫招许封跑埋陋口寸鲁讲捷改毯陨复埃录幸艰耐尔映柯锐阵惠宾雇用语枯狈袁吗念蓄喀广竭发距属督遂私房安在辽窜爆渐公赌佳怨秦气抢处瑞灾嚼瞬况事辅次候傲粗旨已皇右才下礼亮专鸿伞优罐仅所钠沈暴聊桩矢贫勤阿沉来链绍听镇半调岛眠毫殖坊畴剩襄陕尚足栏奔马英证采氛钟奠描浦劲傻凑斡瘤蚀示冯乃逗铆心啥倘囊关前盘微泻脊析狐奎扫宏折素虚益焦远纽哄潘芋遏砖揭泰废予权媒环糊榨削物若岩伴扬诱汉逮纯巧隆续洪渡节湖贯闻健腾陇贡谊傍百蛋墅早党叫趋迷长皂俩旦洼大设餐云烟淤营肾寂坝戴尾染他星锣需互救娱摄贞不伍奢辱绘莎署嘉缘格子昌厦转和孩过白友肿狂玻溢债腊行措汰写挫促殿符捶赵鼓架盐杰掩坑凹向移什振贩垫础勘赔蜜甩橙曹恒副您杯仰依郊商系例原级梅挂程啦伊售较腕轰氨审杀暖炉仇法寄貌亏辞鹿假咱炸梯与韩联帅菜班械醒董耗一扮止活清忍铁丧拒住给库机旅严捅榔财森暗身肋字黄困铸搭绸帆新忆骆误胶强潜萄劫妓闲鬼邀苯谓乡肃鲸旺永姜掖单队逐牢汾沸拘征庭篇碎育掘柱籍别晕附逃村各徘挺五衣梦爷论巢叹纱徊兰肚软贬危刀秀料警捧略鼻克咬久落掌逆共途沾歧辗浙荐负唱走读婴迅欣计瘫契围枚玉芯肠陪短缝逻斥妈汗区腐洛浇银福塔团喷赁番的轮成错垮怖尽彼驻圆腔腰励推近叙外洲愤年混讨挟薄非雷耸召葬款后伦先办器想廊披页谷之茅丽会纷爬芬今粮踏纪弯常脚两兵擅丹沪茶送扣晤体阁冬棍密润癌淫汹膏点笑争烫判值秩萌国巴拥幅溜扇庄站岁乱轿课叶旬膜宴拎抑切感旁仍食稀妹侈症补炮兴藏挥徒追摧费业档伟荷父赛隐仑也遇黑衡检抗桑寞洞租都尸验楚吕凸掏票赣烧号艺喘迟登船海学径吸顽斗模汽智自表患辰美利赫损昏骇均壁根吴使燃遵淡日亨引丑革术渣递辆绳呵观耕囤陷潭偶吁仁高裹遍捐息污列伤迈淹但覆载敌漫斯该秒饲吵菱姐产饭刻南甸草可正返勒稍赴悠步古瘪怎锋抛宽蒲估再细牺秘漠蔽期猜渔粘养盗责谭绒赠男苹资疾藉周或继扰殴故输找耀访算俗般台胖汛忽任薯儿迁鸥态力蓝酋鸡质钢超缩趁奖弘碰当觉擎头控坪戮绿局傅操宵显顶插积第沿春军凯苑柏闯榜天芦容意悉蒙砸氏拼喊洒泄睡桔葡宅露汤账骚豆屁东淄咨萨诺激宜港升特捡杨戚纺佩让澈驾卖兼毛酸厌疗接刊协犯胜必律枢框玄灯降橱记疏将堪璃涵肖蔡镜耶种否巡状翻跟谐丝堤踢乔震览沃哈摔委诉典裁院组椅旭哲破崩面辜郑盼我石浮彩间镑演罩诸祖闷障散鼠似猪宙习浑至缓饼迪九宗慎背甘阻幼名胺杆崖其老启问佛娘隶含脑响赚套速合宪凡跳者愈稳饮很告梳痕察雨遮效稿婆烹话歌裴应岗残孙泼洁样令垂滑她奈完田吃彪杂施轴裔嘴二温啸就婚锈入穆人巨决材艳去注哀刘耻嫩拿股零塌迎渤殊炙订趣莱乘欢罚有祥呛卷谈剐晋世奋败伯抨戈击醉胃际飞说夯能受孝黎揍销牙瓶仪痪总基客要羊拢踩窖敦全玩卓顺倒雏虹妥恐预询握盖盒签宁交梭割知荆织携赎倚药拖午牟刑香菏段缉主谱衫鸣乐俯莉驶枪麻获每执只通讽厅押笔雾你反急涨箱把霄伐厕保漏邯钩肯率本得罢万创净萎挨愿募宋阅禁虎嫁博医血卿够述投除夫搞丰准燕屋赋烂挤金蒂嫌畏灿着省冈赶供耘稽柳买娜瞩失农灵攀罪冷七懂拐志解赢题蔓浆乎邦骑锅园谢额确厂夜江姻席畜炭跃晒性池闭瘦郎扯项痛瓦瑟济撑仿对魏免胎尼坚务须弄钾煤流族松舟鹤妇努廉哪己紧娃菲运臣弃查加最舞针括定膀码旋红憾亩偿极悄六伙讯末三玲慌树湾淀唐俄纠叉累练啊'"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "one_hot #预览2300个种类的字"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0696807a",
   "metadata": {},
   "source": [
    "## 对长图片进行投影法切片"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 99,
   "id": "d146faf0",
   "metadata": {},
   "outputs": [],
   "source": [
    "%mkdir /home/asd/data/train_img"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "6c13e4a8",
   "metadata": {},
   "outputs": [],
   "source": [
    "from PIL import Image\n",
    "import numpy as np\n",
    "import torch"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "dd346244",
   "metadata": {},
   "outputs": [],
   "source": [
    "#切片函数\n",
    "def crop(b,begin_idx):\n",
    "    for i in range(begin_idx,len(b)):\n",
    "        if b[i]==0:\n",
    "            continue\n",
    "        else:\n",
    "            begin_idx=max(i-1,begin_idx)\n",
    "            break\n",
    "    end_idx=begin_idx\n",
    "    for i in range(begin_idx,len(b)-10):\n",
    "        tmp=0\n",
    "        for j in range(i,i+7):\n",
    "            tmp+=b[j]\n",
    "        if tmp==0:\n",
    "            end_idx=i\n",
    "            break\n",
    "    return begin_idx,end_idx"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 103,
   "id": "7a0c6c3e",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 30min 23s, sys: 3min 29s, total: 33min 53s\n",
      "Wall time: 33min 58s\n"
     ]
    }
   ],
   "source": [
    "#对20万张图片进行切片，并将切片好的图分别存放到对应类别中\n",
    "%%time\n",
    "for i in range(0,200000):\n",
    "    path='./data/HandWrite/HW_Chinese/train_data/'+str(i)+'.png'\n",
    "    img=Image.open(path).convert('1')\n",
    "    img_arr=np.array(img)\n",
    "    img_arr=1-img_arr\n",
    "    a=torch.tensor(img_arr)\n",
    "    b=a.sum(dim=0)\n",
    "    crops=[]\n",
    "    b_idx=0\n",
    "    e_idx=len(b)\n",
    "    img=Image.open(path)\n",
    "    while(True):\n",
    "        b_idx,e_idx=crop(b,b_idx)\n",
    "        if e_idx-b_idx<=10:\n",
    "            break\n",
    "        crops.append([b_idx,e_idx])\n",
    "        b_idx=e_idx\n",
    "    p=[]\n",
    "    for j in crops:\n",
    "        box = (j[0],0,j[1],32)\n",
    "        img_new = img.crop(box)\n",
    "        p.append(img_new)\n",
    "    ss=tmp[i]\n",
    "    this_len=len(p)\n",
    "    if not this_len==len(ss):\n",
    "        continue\n",
    "    for k in range(this_len):\n",
    "        char_c=ss[k]\n",
    "        num_idx=one_hot.find(char_c)\n",
    "        if not os.path.exists('./data/train_img/'+str(num_idx)):\n",
    "            os.mkdir('./data/train_img/'+str(num_idx))\n",
    "        png_num=len(os.listdir('./data/train_img/'+str(num_idx)))\n",
    "        map_data = np.array(p[k].convert('RGB'))\n",
    "        map_data = np.asarray(map_data, np.uint8)\n",
    "        pic = Image.fromarray(map_data)\n",
    "        pic.save('./data/train_img/'+str(num_idx)+'/'+str(png_num)+'.png')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "ee0c075f",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "切片文件总数:\n",
      "601345\n"
     ]
    }
   ],
   "source": [
    "print('切片文件总数:')\n",
    "!find ./h_data/ -type f | wc -l"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0aaf82f0",
   "metadata": {},
   "source": [
    "## 对切片进行数据增强"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "09c4af3f",
   "metadata": {},
   "outputs": [],
   "source": [
    "from PIL import Image, ImageChops\n",
    "import random"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "9b90912b",
   "metadata": {},
   "outputs": [],
   "source": [
    "#定义平移方法\n",
    "def ImgOfffSet(Img,xoff,yoff):\n",
    "    width, height = Img.size\n",
    "    c = ImageChops.offset(Img,xoff,yoff)\n",
    "    c.paste((255,255,255),(0,0,xoff,height))\n",
    "    c.paste((255,255,255),(0,0,width,yoff))\n",
    "    return c"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 118,
   "id": "6acdac29",
   "metadata": {},
   "outputs": [],
   "source": [
    "#对图片进行随机小幅度平移和旋转，补齐数据\n",
    "mlen=len(os.listdir('./data/train_img/'))\n",
    "for i in range(0,mlen):\n",
    "    num=len(os.listdir('./data/train_img/'+str(i)))\n",
    "    back=num\n",
    "    while(num<100):\n",
    "        r_idx=random.randint(0,back-1)\n",
    "        img=Image.open('./data/train_img/'+str(i)+'/'+str(r_idx)+'.png')\n",
    "        xoff=random.randint(-2,2)\n",
    "        yoff=random.randint(-2,2)\n",
    "#         deg=30*random.random()-15\n",
    "#         img = img.rotate(deg)\n",
    "        img=ImgOfffSet(img,xoff,yoff)\n",
    "        png_num=len(os.listdir('./data/train_img/'+str(i)))\n",
    "        img.save('./data/train_img/'+str(i)+'/'+str(png_num)+'.png')\n",
    "        num+=1"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6a3ee608",
   "metadata": {},
   "source": [
    "# 构建DataLoader"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "0a4f6c8b",
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch\n",
    "import numpy as np\n",
    "from PIL import Image\n",
    "from torch.utils import data\n",
    "import os"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7ffdaa01",
   "metadata": {},
   "source": [
    "## 读取总类别数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "fd9540c7",
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2299\n"
     ]
    }
   ],
   "source": [
    "#类别总数\n",
    "all_kinds=len(one_hot)\n",
    "print(all_kinds)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0f5caf97",
   "metadata": {},
   "source": [
    "## 构建myDataset类继承DataSet"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "9e812e36",
   "metadata": {},
   "outputs": [],
   "source": [
    "class myDataset(data.Dataset):\n",
    "    def __init__(self,x,y):\n",
    "        #创建5*2的数据集\n",
    "        self.data = x\n",
    "        #5个数据的标签\n",
    "        self.label = y\n",
    "    #根据索引获取data和label\n",
    "    def __getitem__(self,index):\n",
    "        return self.data[index], self.label[index] #以元组的形式返回\n",
    "\n",
    "    #获取数据集的大小\n",
    "    def __len__(self):\n",
    "        return len(self.data)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "f235b0e2",
   "metadata": {},
   "outputs": [],
   "source": [
    "from PIL import ImageFilter"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1a5716bd",
   "metadata": {},
   "source": [
    "## 获取图片，加载训练集"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "id": "617469ec",
   "metadata": {},
   "outputs": [],
   "source": [
    "#获取长度为100的图片\n",
    "def get_df_data(all_kinds):\n",
    "    source=[]\n",
    "    y_train=[]\n",
    "    mlen=len(os.listdir('./data/train_img/'))\n",
    "    for i in range(mlen):\n",
    "        tlen=len(os.listdir('./data/train_img/'+str(i)))\n",
    "        if tlen>100:\n",
    "            continue\n",
    "        for j in range(0,100):\n",
    "            img=Image.open('./data/train_img/'+str(i)+'/'+str(j)+'.png').resize([64,64]).convert('L')\n",
    "            img = img.filter(ImageFilter.SHARPEN)\n",
    "            source.append(np.array(img))\n",
    "            temp=np.zeros([1,all_kinds])\n",
    "            temp[0,i]=1\n",
    "            y_train.append(temp)\n",
    "    x=np.array(source)\n",
    "    del source\n",
    "    y=np.array(y_train)\n",
    "    del y_train\n",
    "    y=y.reshape(-1,all_kinds)\n",
    "    train_features = torch.tensor(x, dtype=torch.float32)\n",
    "    del x\n",
    "    train_labels=torch.tensor(y, dtype=torch.float32)\n",
    "    del y\n",
    "    train_features.unsqueeze_(dim=1)\n",
    "    train_data=myDataset(train_features,train_labels)\n",
    "    return train_data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "id": "920776cf",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(torch.Size([229900, 1, 64, 64]), torch.Size([229900, 2299]))"
      ]
     },
     "execution_count": 56,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "train_data=get_data(0,all_kinds)\n",
    "train_data.data.shape,train_data.label.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "d0a6574f",
   "metadata": {},
   "outputs": [],
   "source": [
    "ll=get_df_data(all_kinds)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "3762411b",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "596.1919831223629"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.mean(ll)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "id": "4ab6ccbf",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(torch.Size([135100, 1, 64, 64]), torch.Size([135100, 2299]))"
      ]
     },
     "execution_count": 46,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "train_data=get_df_data(all_kinds)\n",
    "train_data.data.shape,train_data.label.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "id": "524205b7",
   "metadata": {},
   "outputs": [],
   "source": [
    "#构建分组器\n",
    "batch_size=1100\n",
    "train_loader=data.DataLoader(train_data,batch_size=batch_size,shuffle=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bdb3c36c",
   "metadata": {},
   "source": [
    "# 构建Res-Net 18模型"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bd427b42",
   "metadata": {},
   "source": [
    "## ResNet18网络"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "eb9ae65d",
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch\n",
    "import torch.nn as nn\n",
    "from torch.nn import functional as F\n",
    "\n",
    "\n",
    "class ResNetBasicBlock(nn.Module):\n",
    "    def __init__(self, in_channels, out_channels, stride):\n",
    "        super(ResNetBasicBlock, self).__init__()\n",
    "        self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=stride, padding=1)\n",
    "        self.bn1 = nn.BatchNorm2d(out_channels)\n",
    "        self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=3, stride=stride, padding=1)\n",
    "        self.bn2 = nn.BatchNorm2d(out_channels)\n",
    "\n",
    "    def forward(self, x):\n",
    "        output = self.conv1(x)\n",
    "        output = F.relu(self.bn1(output))\n",
    "        output = self.conv2(output)\n",
    "        output = self.bn2(output)\n",
    "        return F.relu(x + output)\n",
    "\n",
    "\n",
    "class ResNetDownBlock(nn.Module):\n",
    "    def __init__(self, in_channels, out_channels, stride):\n",
    "        super(ResNetDownBlock, self).__init__()\n",
    "        self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=stride[0], padding=1)\n",
    "        self.bn1 = nn.BatchNorm2d(out_channels)\n",
    "        self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=3, stride=stride[1], padding=1)\n",
    "        self.bn2 = nn.BatchNorm2d(out_channels)\n",
    "        self.extra = nn.Sequential(\n",
    "            nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=stride[0], padding=0),\n",
    "            nn.BatchNorm2d(out_channels)\n",
    "        )\n",
    "\n",
    "    def forward(self, x):\n",
    "        extra_x = self.extra(x)\n",
    "        output = self.conv1(x)\n",
    "        out = F.relu(self.bn1(output))\n",
    "\n",
    "        out = self.conv2(out)\n",
    "        out = self.bn2(out)\n",
    "        return F.relu(extra_x + out)\n",
    "\n",
    "\n",
    "class ResNet18(nn.Module):\n",
    "    def __init__(self):\n",
    "        super(ResNet18, self).__init__()\n",
    "        self.conv1 = nn.Conv2d(1, 64, kernel_size=7, stride=2, padding=3)\n",
    "        self.bn1 = nn.BatchNorm2d(64)\n",
    "        self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)\n",
    "\n",
    "        self.layer1 = nn.Sequential(ResNetBasicBlock(64, 64, 1),\n",
    "                                    ResNetBasicBlock(64, 64, 1))\n",
    "\n",
    "        self.layer2 = nn.Sequential(ResNetDownBlock(64, 128, [2, 1]),\n",
    "                                    ResNetBasicBlock(128, 128, 1))\n",
    "\n",
    "        self.layer3 = nn.Sequential(ResNetDownBlock(128, 256, [2, 1]),\n",
    "                                    ResNetBasicBlock(256, 256, 1))\n",
    "\n",
    "        self.layer4 = nn.Sequential(ResNetDownBlock(256, 512, [2, 1]),\n",
    "                                    ResNetBasicBlock(512, 512, 1))\n",
    "\n",
    "        self.avgpool = nn.AdaptiveAvgPool2d(output_size=(1, 1))\n",
    "\n",
    "        self.fc = nn.Linear(512,all_kinds)\n",
    "\n",
    "    def forward(self, x):\n",
    "        out = self.conv1(x)\n",
    "        out = self.layer1(out)\n",
    "        out = self.layer2(out)\n",
    "        out = self.layer3(out)\n",
    "        out = self.layer4(out)\n",
    "        out = self.avgpool(out)\n",
    "        out = out.reshape(x.shape[0], -1)\n",
    "        out = self.fc(out)\n",
    "        return out"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8aafb28d",
   "metadata": {},
   "source": [
    "## 实例化模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 68,
   "id": "6b562a37",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 使用GPU进行模型训练\n",
    "dev=torch.device('cuda:0')\n",
    "net=ResNet18()\n",
    "net=net.to(dev)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 69,
   "id": "5df01011",
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([1, 2299])"
      ]
     },
     "execution_count": 69,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "net(X[0].to(dev)).shape"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c0f60327",
   "metadata": {},
   "source": [
    "# 创建交叉熵损失函数和Adam优化器"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 70,
   "id": "9b50938e",
   "metadata": {},
   "outputs": [],
   "source": [
    "loss=torch.nn.CrossEntropyLoss()\n",
    "loss=loss.to(dev)\n",
    "optimizer=torch.optim.Adam(net.parameters(),lr=0.001)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "94f71b04",
   "metadata": {},
   "source": [
    "# 训练模型"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c16b6a78",
   "metadata": {},
   "source": [
    "## 编写ACC计算函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 71,
   "id": "a64ee1d5",
   "metadata": {},
   "outputs": [],
   "source": [
    "def acc(y_pre,y):\n",
    "    all=torch.sum(torch.argmax(y_pred,dim=1)==torch.argmax(y,dim=1))\n",
    "    return all/y.shape[0]\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e7d71c6c",
   "metadata": {},
   "source": [
    "## 训练模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a0ba169c",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%time\n",
    "# net.train()\n",
    "# batch_size=200\n",
    "# for ii in range(5):\n",
    "#     train_data=get_data(ii,all_kinds)\n",
    "#     train_data.data.shape,train_data.label.shape\n",
    "#     train_loader=data.DataLoader(train_data,batch_size=batch_size,shuffle=True)\n",
    "for epoch in range(30):\n",
    "    for step,(X,y) in enumerate(train_loader):\n",
    "        X=X.to(dev)\n",
    "        y=y.to(dev)\n",
    "        y_pred=net(X)\n",
    "        optimizer.zero_grad()\n",
    "        cost=loss(y_pred,y)\n",
    "        cost.backward()\n",
    "        optimizer.step()\n",
    "        if step%50000==0:\n",
    "            print('epoch:',epoch,'loss',cost.to(torch.device('cpu')))\n",
    "            with torch.no_grad():\n",
    "                print('acc:',acc(y_pred,y))\n",
    "    if epoch%5==0 and epoch!=0:\n",
    "        net.eval()\n",
    "        with torch.no_grad():\n",
    "            net=net.to(torch.device('cpu'))\n",
    "            test(net)\n",
    "        net=net.to(dev)\n",
    "        net.train()\n",
    "torch.save(net.state_dict(), \"./data/model-resnet.pkl\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9458af79",
   "metadata": {},
   "source": [
    "## 验证模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "id": "7a9c954b",
   "metadata": {},
   "outputs": [],
   "source": [
    "tmp = []\n",
    "a_sum = 0\n",
    "real_num = 0\n",
    "with open('./data/HandWrite/HW_Chinese/test.txt', 'r') as f:\n",
    "    for lines in f:\n",
    "        if lines.startswith('\\n'):\n",
    "            continue\n",
    "        ib_idx = lines.index(' ')\n",
    "        s = lines[ib_idx:-1]\n",
    "        tmp.append(s[1:])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "id": "6ae4c32d",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'项规定确保政府'"
      ]
     },
     "execution_count": 36,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tmp[4]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "id": "4d58d1d0",
   "metadata": {},
   "outputs": [],
   "source": [
    "import random\n",
    "def test(net):\n",
    "    tmp=[]\n",
    "    net.eval()\n",
    "    a_sum=0\n",
    "    real_num=0\n",
    "    with open('./data/HandWrite/HW_Chinese/test.txt','r') as f:\n",
    "        for lines in f:\n",
    "            if lines.startswith('\\n'):\n",
    "                continue\n",
    "            ib_idx=lines.index(' ')\n",
    "            s=lines[ib_idx:-1]\n",
    "            tmp.append(s[1:])\n",
    "    #x_s=random.randint(0,10)\n",
    "    for i in range(0,1):\n",
    "        t_a=0\n",
    "        t_r=0\n",
    "        path='./data/HandWrite/HW_Chinese/test_data/'+str(i)+'.png'\n",
    "        img=Image.open(path).convert('1')\n",
    "        img_arr=np.array(img)\n",
    "        img_arr=1-img_arr\n",
    "        a=torch.tensor(img_arr)\n",
    "        b=a.sum(dim=0)\n",
    "        crops=[]\n",
    "        b_idx=0\n",
    "        e_idx=len(b)\n",
    "        img=Image.open(path).convert('L')\n",
    "        img = img.filter(ImageFilter.SHARPEN)\n",
    "        while(True):\n",
    "            b_idx,e_idx=crop(b,b_idx)\n",
    "            if e_idx-b_idx<=6:\n",
    "                crops.append([e_idx,len(b)])\n",
    "                b_idx=e_idx\n",
    "                break\n",
    "            crops.append([b_idx,e_idx])\n",
    "            b_idx=e_idx\n",
    "        p=[]\n",
    "        for j in crops:\n",
    "            box = (j[0],0,j[1],32)\n",
    "            img_new = img.crop(box).resize([64,64])\n",
    "            backb=img_new\n",
    "            img_new=np.array(img_new)\n",
    "            img_new=torch.tensor(img_new,dtype=torch.float32)\n",
    "            y_pred=net(img_new.reshape([1,1,64,64]))\n",
    "            p.append(torch.argmax(y_pred))\n",
    "        #img.show()\n",
    "        p=p[:-1]\n",
    "        ans=''\n",
    "        for nn,aa in enumerate(p):\n",
    "            ans+=one_hot[aa]\n",
    "            real_num+=1\n",
    "            if(nn>=len(tmp[i])):\n",
    "                break\n",
    "            if one_hot[aa]==tmp[i][nn]:\n",
    "                a_sum+=1\n",
    "                t_a+=1\n",
    "            t_r+=1\n",
    "#         print(tmp[i])\n",
    "        print(ans)\n",
    "#         print('h',t_a/t_r)\n",
    "    print('test acc:',a_sum/real_num)\n",
    "    #print(real_num)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "id": "bff69de1",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "test acc: 0.9549851584861656\n"
     ]
    }
   ],
   "source": [
    "new_model=ResNet18()\n",
    "new_model.load_state_dict(torch.load(\"./data/model-resnet.pkl\"))    # 加载模型参数     \n",
    "test(new_model)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f9d9dc8b",
   "metadata": {},
   "source": [
    "## 显示分割效果"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "id": "59e4c533",
   "metadata": {},
   "outputs": [],
   "source": [
    "%matplotlib inline\n",
    "#The line above is necesary to show Matplotlib's plots inside a Jupyter Notebook\n",
    "\n",
    "import cv2\n",
    "from matplotlib import pyplot as plt\n",
    "import numpy as np\n",
    "def accessPiexl(img):\n",
    "    height = img.shape[0]\n",
    "    width = img.shape[1]\n",
    "    for i in range(height):\n",
    "       for j in range(width):\n",
    "           img[i][j] = 255 - img[i][j]\n",
    "    return img\n",
    "\n",
    "# 反相二值化图像\n",
    "def accessBinary(img, threshold=128):\n",
    "    img = accessPiexl(img)\n",
    "    # 边缘膨胀\n",
    "    kernel = np.ones((3, 3), np.uint8)\n",
    "    img = cv2.dilate(img, kernel, iterations=1)\n",
    "    _, img = cv2.threshold(img, threshold, 0, cv2.THRESH_TOZERO)\n",
    "    return img\n",
    "def showResults(path, borders, results=None):\n",
    "    img = cv2.imread(path)\n",
    "    # 绘制\n",
    "    print(img.shape)\n",
    "    for i, border in enumerate(borders):\n",
    "        cv2.rectangle(img, border[0], border[1], (0, 0, 255))\n",
    "        if results:\n",
    "            cv2.putText(img, str(results[i]), border[0], cv2.FONT_HERSHEY_COMPLEX, 0.8, (0, 255, 0), 1)\n",
    "        #cv2.circle(img, border[0], 1, (0, 255, 0), 0)\n",
    "    plt.imshow(img)\n",
    "    plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "id": "ef3f0263",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[(243, 21), (266, 28)], [(185, 21), (194, 28)], [(249, 12), (263, 17)], [(67, 11), (83, 24)], [(101, 10), (120, 27)], [(145, 9), (153, 17)], [(6, 8), (19, 23)], [(177, 4), (196, 26)], [(61, 4), (67, 28)], [(247, 3), (263, 7)], [(211, 2), (226, 25)], [(6, 1), (15, 14)]]\n",
      "(32, 280, 3)\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXAAAABJCAYAAAAkG33uAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/YYfK9AAAACXBIWXMAAAsTAAALEwEAmpwYAAAsn0lEQVR4nO2deXAc13ngf2/uA3NhAAwO4iIEguAFkSJFSiR1RrJ1WdoosrWJr/LGdtmrOE7i3XV2bZUTV6WSlI8k9sa2duNrvU7ssta2LidyKFkWTZESSZEERdwHcWMwgxnMfff+MdNNgARIEBhcdP+qpjDomen+Xr/ur9/7rickSUJFRUVFZeOhWWsBVFRUVFSWhqrAVVRUVDYoqgJXUVFR2aCoClxFRUVlg6IqcBUVFZUNiqrAVVRUVDYoy1LgQoh3CyG6hBC9QojPFksoFRUVFZVrI5YaBy6E0ALdwH3ACPAW8B8lSbpQPPFUVFRUVBZiOSPwW4FeSZL6JUlKAf8CPFocsVRUVFRUrsVyFHgNMDzr/5HCNhUVFRWVVUC30gcQQnwM+BiA1Wq9ZevWrfN+r7sb0unF77eqKkRJiQm9Xo8QohiiqqwDkskkiUQCm82GRrN2PvZEIoHBYFhTGW40QqEQOp0Og8GATrfiqueG4tSpUz5Jksov376cszgK1M76f1Nh2xwkSXoGeAZg79690smTJ+fdWX093Hcf7Nmj/BJJkpiYmMDrnWJycoJ0OsNtt93J5z9v5amnfkh5eY5NmzbR3NxMdXU1QohlK3PZJxCJREgmk0xMTBAMBhFCEI1GkSSJZDKJwWDAaDSi0+mw2+2FNtRTUlKiXpzLYGxsjJ6eHtxuN9u3b1+Th7MkSRw/fpzt27crfaty/fzoR/Daa/J/EsPDwxgMBux2B2az+br2dfvt8P73F13EDYMQ4uJ825ejad4CmoUQjeQV95PA7y9jf7zrXfDEE/n3uZzE0NAQFy5cYHJykuHhvLXmIx85xOc/Dx6Ph7Gxt/H7/USjUdLpNA0NDcs5fOG4OXw+HyMjIyQSCUZHRwkGg5jNZuLxOIlEgmQyiV6vR6fTodFocDgcpFIpJEmioaEBp9O5bDkA5VgOh6Mo+9sIaDQatFotyWRyTeUwGAy/FTO7ZDLJ1NQUkUiE5uZmtFpt0fb9+uvws5/Bvn35/7PZSrq6hjCbs+RyOaamfACYTEY8Hg9CCGKxGMlkkvr6+oIsglOnIJVaWQXe1QWdncXbn8mU12crzZIVuCRJGSHEU8C/AVrg25IkvVMMoXK5HIlEgpdffpmBgQGsViuSJOFwOLBarQAcPnwHnZ053n77bV577TVGRkb48Ic/jNFoXNaNl81meeedd+jo6ECr1aLRaLBYLJSVlWG32/H7/QghSKVSxONxYrEYwWCQ8fFxDAYDDodjyQpckmBy8tL/U1Mhpqam2LbtkgJ3OvMXx41ILpdjYmKCjo4O3vve966JDPIMrLKyEoPBsCYyLIZ0Gvz+5e/H7w/z2msn6Ovr41Of+hRGY16BGwxQWrr8/d9+O/zkJ/lrOxiM8u1v/5y6ujoAfvOb3yBJEhUVFdx3331oNBouXrzI2NgYH/nIR7BYLAgBf/AHy5fjWvz4x/DFL0q4XBKxWBydTkculyOXywGg1WrIZrNAvi2SlCN/qUiAQJIkhBCYTCYkyYDFAqNX2COKz7Lm+pIkvQS8VCRZ5H0SjUZ5/fXX6evrY9++fRw6dIjKykoAotH89wwGA/fffz8Wi4UXX3yR06dP43K5eOyxx5Y1ejIYDNxzzz3cc889i5Y3k8nwj//4j+zatYuysrIlHRfyo4yaGshfMxJQXnhd4mc/g0dv0FifQCDA0NAQQ0NDc2Ydl4e6rtTIWD5OJpNBp9Ot6xH4hQtw882zt8w+R4uVWwLcwO8C8JWvyNsE99wDR44sW0zyptD8u5KSEmUgduutt/JEYbotn3chBG63G6PRSCaTKcbBFydh4fj790u89FKUb33rW7S2tuLz+ZienkaSJKqqqhgYGECSJOLxOJFIhEQiQS6XQ6fTEYvFKCkp4fHHHyccvptPfGJ1ZF+XxtpwOMwbb7yBw+Hg0KFDV1WKt9xyC3a7ne9///scO3aMu+66C7fbvWp2aPmBY7Va8Xg8WCyWZe/z7Fno6/sV58+/g9Fo5KMf/SgA27cve9frmt/85jdMTEzwrsvmnrlcjmQySTgcxu/309rauiLKVb45f/WrX3HLLbesawUOYDTC2BgIAT/4wQ8IBoPcfPPNHDp0eFG/f+utk7S3t1NfX8/bb7/N7/3e41RXV/PlLxs5dao4Mvb29vH1r/8Ci8XChz70IYQQ2O12xbeQzWb55Cc/yV/8xV9QWVmJz+ejvb2dhx56qDgCLILp6WnCYQN9fRP8t//2VZqbm3nhhRdIJBJks1mEEHR1dTEzM4PJZFJm5VVVVTQ2NioP/LvuuovKykr+9V9XTfT1p8C9Xi/t7e3EYjHq6+uxWq0L2uUymQyhUIhEIsHOnTs5cuQIx44d4/Dhw8saCV8PuVyOQCCAEEKxiS8XhwN27NhEJuPD5/PhcuW3r3N9sizOnDmD3++noqKC1tZWRkdHGRwcpLe3FwCTyYTBYCCXy9Ha2lr040uShM/n44033sDv92Oz2YpqD14JhMib1DQa+N3fvYeuri4GBro5cmSSxx9/fM4DKJ1OEwqFKC0tRQjBwMAAGs0MW7d62L27lfPnXweClJRUYDIZiyZjdXUVDz30EFNTU5w4cQKNRoPRaESj0SimUtlMAXmFnkwmV/XhmU6nyWY1mM1mWlpaaGpqoq6ujng8Ti6Xw2g04nK5CAQCGAwGKisrsdlsWCwWLBaLYj4pLS1Fr9evmtywDhV4IpEgEAiQSqWorq5eMExwZiZIIhFkZmaGdDpNZWUlOp2OoaEh4vH4qsmby+UIBoNYLBY0Gk3RLjyz2YzRaJxzcW80JicnCYVCGAwG6uvr5/2OJEnkcjn6+vooKSnBZrMxMjKCTqcjFApRUVGBTqfDaDRiNBpXTKl6vV76+vqYmZnB7XZvuBDCmpoaJVLqlVde4fHHH1c+kySJUCjEsWPHePjhh5EkidHRUYQQNDU1UVZWxvbt21fk3FosVurr67Hb7UxMTOB0OhXfQiqV4ty5c9TX16PX65mZmSGXy1FbW3uNvRZbRgtGo45QSMcbbxymo8OJVqslnU4jSRJ6vR6r1UosFkOr1eJyuWZdi1fe7x0dqyf7ulLgfX1gNhvo7y9lYqIGn6+BM2e0zLaGyLr52LEo6bSfTCaL0VgCmKmsrKKkpGTFR06SJCl2s2w2Szgcxm63F/W4kUiEUCikRLfk2VhD8IsXLyqKeSEFDjA6Oko6neamm25Cq9UyMjJCU1MT5eXl7Ny5E6OxeCPC+UilUgwNDdHX14fNZqOlpWVDKW+Zqqoqtm3bxk9+8hPi8Thms1kZUEQiEd566y0OHDiA3W7H5/Phdrupq6tDp9Nx8OBBpqamrvA3FAOtVovb7cbpdDI8PIyp4IVPJBL8+te/xuVyEQwGmZ6eJhaL0dbWVnQZrobdbmfz5nwoc2/vnmv/YBHs2lWU3VyTdaXAn35aQogKstm7EOJuXnxRx1yldckh8vGPV6LV5mO/cznQaNL8+Mdj3HvvvcoFUgxkZZ3L5eYo7Uwmozgwo9Fo0RNPurq66O7uxmQykU6nCw8HDRtJifv9fnp6ejCZTDzyyCNXfC5JEtlslh/+8Id88IMfVEbbu3fvXlU5JyYmmJycJJFIUF1dzU033aT0ZTq9+AQzkylvzlgrhBDYbDZuu+02Ojs72blzpzKDNRqNVFVV8dJLL3HHHXeQTqcxGo2KCcDj8XDkyBE8Hg9QsiKy6XQ6qqrygyzIPzjb29uVmYPs3/id3/mdoh//WvzhH+ZfG411pcC/+c0obverPPfcczQ2NvLnf/7ncz7P5XJ4vVE2bbLxla/8jMceu42qqmqOH4cHHtCtiOMjnU4zMjLC8ePHuXjxIolEAovFopg48okJdjweT1EVuMlkQqfTEYlEFGWeSDwIXF8CxFry7ne/m9bWVtrb2+f9PJvN4vV6+bM/+7M1TX4aHh4mnU7T1NTEgQMH5syknn4a/vZvF7efU6cujwxZfVKpFBcvXmRwcJDm5mbFJpvL5YhGo8RiMV566SUefPBBxVSRzWY5fvw4ZrN5xWevs0fXQghKSkr42te+xte//nWy2eyq25A3OutKgY+MDKPVTrN5cwPvfe8TaDSXHHeSJDEzM8OvfvVr4FHe9a778HjMaLXyqCf/xWKYoCVJYnx8nFAoxPDwMFNTUwgh2LlzJ1u2bMFisRTiPSWmp6c5c+ZMURM/hoeH8Xq9TE1NMTY2xg9+8AMaGxvJ5XLEYjECgbyTp1gJQ8VibAwOzwmAEKTTNaRS5RTC9+cgSVqy2Qq0Wm2h365+/rZuhRdfLI6s8mzq7NmzSJJEdXU1ZWVlmEymOf0oSVBZ2cv99/8LJpNRCXGTIw9qamp44on3sWNHceRaLvJI95ZbbkGv1+Pz+RgfH2doaAitVksikcDj8cxR1nIkVSgUKnr4XmdnJ//wDy/zgQ98AKfTqZzbYDDI5OSk8vAOBALs3LmTPXv2kEgkijqLvpFZVwp8eHgYp3OG6upqNm3aNOezQCBAd3c3/f39AIWU9ZUzJ2QyGdxuNxaLhYaGBsWR5nK50Gq16HQ6JElS3sue9WLw8ssvk0r1EI/HKS8vZ//+/Wzbtg2DwcA3vgE//7mmMC1e3nEeeyz/KhaZDAwMwDPPMMtvoS+85kMgX4LpdIrBwUEuXrxIPB7nzjvvLISa5fv4lVfy4ZXFIpvNcu7cORKJBKFQCKfTSSwW4+jRo+zcuTMvnRAkkyZMJom6ujQNDTW0tLTQ19dHb28v4XAYs1lDfX2GfHXltTdvyQp8fHyc733ve6TTafR6PTabjaamJrLZLBUVFXPs4/JIeCUc5hqNBo1Gw+DgIG1tbcoxw+Eww8PD3H333Vy4cIEHH3wQj8dDWVmZWoriOlhXZ2p6ehq9Xs+2bdvm1EpIpVKMjo7S2dk566LTrGhYncViweFwUF5+Rf2YOcimjnzW2NIEkkOngsEY4C4Uc8oPWc1mM/v376e6uhqdTjAxMUEkkq/NcslWe+m40WiE7u5utFotra2thSnplXIdOQKbNxdXgUN+BvSBD7Coh4vsWxgZGWF0dBSXa4wtW6LY7XbuvlvC4bg0o4rFiqfAU6kUfr+f0dFRnE4nDoeDdDrNwMAA4+PjlJeXU1FRoTyQ7XY7t9xyC7W1tWzZsgWz2UwgEFCiJlbC8bc48sdNJlOMjY0pGcHhcJhkMonRaKS0tBSn00lFRQU2m42ZmRnq6urmjHDl2OyVKAwn50ecOHGCTZs2KTZ3eQR+4cIFent7qa2tJRqNYjKZsNlsRZXhekil4Nlnl78fs7n499Z8rCsFrtFoqK2tZf/+/XO2B4NBent76evrY8eO/Qv8ungIIZQ48tlZYpIkkUqllGmmnK2n0+mwWq1LHoFnMpnCiGQMSXJz55134nTO0N/fz/T0NDU1l6r0PvDABRoazqLVavnYx+oLpQMu7WtoaJpvfetZMpkMf/zHf0x5efm8dsU77liSqEUjl8uRyWSIx+O89dZbvP3225SXl7Nv3z4OHjyoKHe5KuDCo/jrQzYX9PT0KPVstm7dyunTpzl79iwOhwOfz0dzc3NhZgUej4n3vOc9yj6ampro6enB6/XicDjQanVrFqMfCoWYnvbz2muv0dvby8zMDKFQCI/Hw8MPP8z27dtxOBzE43EGBgbo6enh0KFDcyJ7hBA4HI4Vqf9SUlJCTU0Nzz33HDt27KCiokKJuQ8EAjz//PN4PB46OjowGAzcfPPNVFVVFVWG6yEahd///XxG9JW3c14XyNdmNpstxJDnkKSccu7SaR1Op/W3T4Hffvvt7Nmj4/KZXEdHJ729fZhMZu68866r7mP2aKgYF6MchSIr51OnTnHxYr4wWENDAzfffLPi/V+qAjca88V8nE4PQsCOHTsIhdpJpVKkUqk537Xb7VgsFuLxuFKbYTZOp5O7776bZ555hp/97Gc8+uijcx4AK49UqBVx9fMfjUaV6I+6ujoefvjhK+rYzMzM8MILL3Dw4EGgqSjSpVIpwuEwoVAIl8vFvn37CIfDcwo6HT589UzGrq4uAoEAFRUVa1Ix8VLKf5Z/+qdvMzjYj8vl4uDBg7S0tPDTn/6Uw4cPs2fPHuXhnU6nmZqaoqOjg0wmoyhwOQmlrq6O559/nvT11HReBA6Hg927d/Pkk08yMjLCyMgITqeTcDhMNpvlE5/4BOXl5Qgh+PGPf0w4HC7q8ZdKe7vEfC6mTCZDIpEgGAwyMjJCR0cHXq+XSCRCSUkJ2WyW8+cb+fWvl1XXb9GsKwX+2c9W87nPXemIzGYPkssdAOCv/urqI7E333yT0tJSKioqilLF7+jRowwODrJr1y7a2trYv38/27dv58SJEwSDQYAViRkeHBxkcnJSCbmSyWazaLVaTCbTvA6nkpIS9u7dy3e+8x0ikci8Sn4lkaR8SvyBA7uVwmPzUVJSQkVFBadPn2Z4eJjNmzdfMQKcmcnPQooZF+zz+ZiYmKC6upq2tjY0Gg3vvPMOXq8Xt9vNQvXqZ/Pyyy+TzWbZt28fe/fuLZpsi6Wrq4vnn+9Gp3uEp576z0BeCWs0GiKRCC0tLXi93jlRHYlEgoGBAW699dYrZmS5XA6NRoPX671iwFAMTCYT999/P3//93/P+9//fsrKyjh16hTnzp2bY6K8lrlyNZmamqKvb4iuri6mpqYoKytjdHSU8fFxtFotwWCQSCSC1WpV/GLBYBCbzYbVWvwwzIVYVwr885/XINeQkmOsf/GLX5DNZmlubmbHLFf/QpXS2tvbCYfD3HrrrYWR2/Kw2WzYbDai0ShCCLRaLYFAgOrqakW5yoq0mCMxIQRms5nS0lKy2SzT09PkcqWKg2f2KCr/1D+PyWSioaEBrVarXFhr4RA6e/YsbW1br+oX6Onp4cSJE+zcuVOpQLht2zbcbjeQ7/+BgQFisVjRnGtDQ0PMzMxgs9mora1VojCGh4cJBoN4PB6amhYe6UtSvsSxRqPB4/GwadMmtFotq20Cr6ur4/bbywGBXm+YM9VPp9N4vV7a2trmhARmMhlmZmZ45JFH0Ol09Pb2Mjw8zOjoKCMjIzQ3N9PS0nLFgKEYyPdNKBRSTI65XI54PD7HqSlnPa4HfvjDf0avj+D3+5mZmVEyc81mMyaTifr6esrKyigpKcHj8RAMBpXSH6+8YuUXv1gdOdeVAm9pyZefhHw98LNnz2OztVNRUcHevQ3Ml9+RSqWIxTJAvohUZWUl/f39+ItRa5O8E9Fut8+xGdpsNux2uxJKqNfrSSaT+P1+nE5nUZwwclRLMBikp6cHjUaDJLkwGg0YDAZSqZRy8U9NTeH3+wvheEL5bTFT+xdPPrRyoXA0r9dLJpMhlUpRU1NDbW0tVVVVBINBAoGAUiPDZrNRVlZWVLus2WxGp9NhMpkURZXL5UilUhgMBlwu11VnDQD9/f1YrVZqa2uVGtarrcAtFgtu99yiaXJUR19fH3q9nrq6OkWBT09Pc/HiRVKpFC6Xi87OTs6cOUMmk1FK+Gq1Wh544IEVUeAycvIb5GetswcX0WhUSSxaK4LBIMeOXQBuw2DQ43aXYbPZyGazlJeXYzablRwQl8uFw+FAr9dTUlJCNBqlrKwMvV6Py7V699y6UuAy2WyWmZkZ3nzzTZLJJBUVFZQWhtySJJFIJEilUiQSCcLhMKOjEtAMQG1tLdlsVpniLPeC1Gq1GI3GOTe22+1WVubx+/1KXHAoFMJsNi9bgU9PTxOPx5XEi4GBAW666SYgb/eUCwLlw9yS9Pb2Mj09TTqdVkaScmjYWhRkyj9sJMW+Cpfstl1dXcoNceuttxaUkZtwOKxEdcgFhKqrq7FYLEVrg1zIabbJK5FIAOByuaisrJzXHBYI5BcnAHj11QzJ5GYslgb0eid6fd5stFhLlTyzLE652rxTfWrKi9/vp7+/n5GRESorKxW7siRJeL1euru7yWQy+Hw+Tp48ydjYGHV1dZSXlzM2NobdbqepqWlV4q9zuZwy0JAZHh5WFkdZK5LJZGHhmNuIx28mlbIgSTmMRh1OZ70irxAGQiENodDsXzvo68u/u3Bh9WRedwo8l8sRiUQ4efIk3d3dHDx4kAMHDije63Q6zeDgoJKckI8PdyMr8MnJSaLRKGNjY/T29nLzMlPj0uk0qVQKrVarlJaUPdCTk5OcOXOG8fFxrFYr25dR7/VSfRXB66+/ztTUSSYmJhQTTr5OiGB0dJTS0rwDTavVMjAwwOnTp5UpqNVqJZ1OU1JSQltb2xqEZIkFY3lzuRxHjx7F5XJhs9mU2ONwOIxGoyEajSp2W3mVpUvx9flzsxzmexBMTk4Sj8epqKigsbHxis+NRrhwQeLd784Vog/uLCjfuYreYFhcGr1cvbK0tFSZMV0v+Wsl/3dsbJyf/OTHaLVatm3bxj333MPr8tOm8N1gMMjY2BipVIqXX36Z4eFh9uzZQ3V1NalUis2bN3PnnXcuezGUayGHKcZiMeLx/KIJqVQKvV7PkSNHaGtro7m5ecWOfy08Hg9PPvk+/st/gb/7u9uXta/VCqRZdwrc7/fT3t7Ov//7v1NfX899992n3OiBQICjR49y/PhxYrGYkkFXVVWp/N5ut1NWVobT6SxKEaRkMkkgECgsATVFfX093d3dymjRYDDQ2Ni47As/k8kwOjoBbOK1117D7Y5gsViora3l4MGDyv7lMpZy6OF3v/td7HY7jz76KOXl5QwPD/Pqq6/S3NxMQ0PDiheCmg+32z1vTLFc0vSOO+5gz6XFTxkfH6exsVEJ4evu7mb79u0cPHhQWVYum82RX/ipuPzbv/0b09PTbN68GZdct3cWX/gC/MmfhOjq6iIUCtHd3c3jjz9eqBly/SSTSU6dOoXL5aKtre2614aEvNkwEkmSyZj5yle+wp/+6aepqanBYDAwNjbG1NSU8t1EIqE8COXZ6Mc//nGcTicjIyN0dXUhhFAWTFkphBA88MAD2Gw2nn/+edrb23G73Xzta1/j05/+ND6fD6vVqvhA1gqHg8tG1uubdaXAp6amOHPmDMePH0er1XL48GGOHTvG+Pg4gUCASCSimEXuvfdeGhoaKC0t5dw5K1/6Un4f9fX1WCwWJTRsubWjS0tLCYVCBINBNBoN8Xic1tZW5Rg9PT3LmuLncjlGR0c5e/Ysg4NjSNJH+eQnP0k83onf78fhcMxRhOFwGI/HQ2NjI6+88golJSU89thj1NXVkUql0Ol0VFZWsnnzZmZmZpT43tWsricXvb+cbDaL3W6nv7+f0tJSWltbFWflPffcg0ajwefzMTY2xoc//GHF3ADFX4VHnvHEYjFsNhsul2te+6sQkEolGRsbpaOjg8cffxyn07GkuG/ZPGSxWC6rMrl4xsfHGRwc5MSJKHr9vfzlX/4FdrtNGc3LjjYZnU7Hrl272Lp1K2azeY75LZvN4nQ6OXz48Kr4Snbv3q34i6qrq3nf+95HZ2cnTz/9tLIU4VovorHRau6vKwXe0dFBKHSKoaEh3G43R48eJR6PMzMzg0ajobKyUhmRezwebDYbBoMBk+mSsnC5XGg0GmKxGFF5/bVlUF5ertxwcsalwWBQllGKx+PLGuVevHiR4eFhtFqtEpLm8Xi4eLGLWCx2hVLR6bSk03H8fj8+n48777yT2tpaTCYToVCIaDSKxWLh/PnznDt3TnEMOZ1Oamtr2bZt24rfJDMzQcXOOZvOzk5KS0uRJAm/34/X61Wm1GazGafTyYEDB9i2bRsmk4lIJILNZluxqX0qlSKXyymx9fM9dHK5nDLyTqVSVFRUXHekRCwWUzIkIT8Kr6mpWdKDXy4xbLGYAYHT6ZpjupEjkH75y1+i1+tpbGykrKxMMdnInDhxAp1OR1NT06o4DmWbd0dHB9XV1YrC3rp1K6+++uqcOuEqi2ddKfDh4WGy2SHFsdTV1UVDQwP19fW4XC5qa2uVp7gQYt6bWnbCpFKpoqxsLq+6MR9yCnzpEld/nZqaYmRkhGAwiMPhoLl5C0Lk1+UMBoNKRt1sEon8KuK5XI7GxkZF2fn9fiYnJ0mn02zevBmdTkd/fz+Tk5Nks1kMBgODg4NoNBq2bNlCsc0Rs234tbV1Vyg5SZLo6+vD5XJRVlaGy+Uik8kQi8UQQijefHmpLdl2q9Pplmwrvpa8kUhEcZwtZMqQq/iNjIzgcDiu6XyU/TSxWIxIJEI0GmVmZga/348kSYqzVC6de70YDAZl5nA5iUSCmZkZxbFdVlZGZ2cdkqRTFiuWOX1ah8PhYPPm0jmjzpVeyayjo4Oamhql9ntpaSn79+8nHA7j9Xoxm81XrR1fDLxeeP75FT3EFbS0TNPSki16rPu6UuDJZEIxAbjdbpLJJDt37mTHjh2Ul5df1xNaTnMtJnIqvV6vVyItIF9IfykK5uLFi/j9frLZ7JzRnxACv99PIpG4wi4bDAbwer24XC7uvvtutFot4XBYKa7kdrvZvXs3u3fv5q233qK/v5+xsTHGx8fp7OwkEokUYsvdFLP7M5kMkUgCIWzccccd89ZCmZiYoLW1le3bt+N2u4nFYvh8PiwWi6IY5XMqSRIjIyPKqijFRk7nNhgMuN3uBaOV5DDDSCSC0WjE5/ORy+WU0axsipBDNtPpNOFwmMnJSfx+P1NTU8RiMaxWq6K4rxZrfi3cbjder5dAYOqKz+LxuBJSetNNN1FTU8Pf/Z2b06dzlJQEKCmxEo8nMBqN6PW7r5hx9PfDq68uWbRFEQwGaWpqUq5rIQT33Xcf7e3ttLe3EwgEKCkpoaSkZEVS+yG/cMxHPwrL6AbgUkq9XNc+m80U/mYLCXRy3oiNj31snD/8w+TqK3AhRC3wfcBDPhTgGUmS/l4I8QXgo4B8Jf33wir1S6atbQ8PP7yNmpoaHA4H58+3s3fvvlkJK/P/7vI8D41Go9TZKDYdHR1KQSM5KWGpkR5WqxWDwYDP56Onp4eJiQCS9AjpdJpMJoPZbL5iBJ7N5gqJHLcrSuTs2bMIIdi6deuc0cu+ffvYt28f0WiUzs5Ovvvd73Ls2DE0Gg2Tk+8DipNiL0kSU1NTvPHGeeD+Bb+n1WoV57JOp0On0xEMBnE6nYoCn12q9fXXXyeZTBYU+PKjUGaTy+UYHBzEYDBQW1s7rwNTxmw2U1NTg8/n46c//Sl1dXXKZxaLBa/Xi9VqxWq1KqatTCbDjh07lAgqOQZ9uQrJbreze/dustkdfPnLUmHmk9+n0+mkoaEBs9nMgw8+WHBcWtm589c88cRJHnvsMY4ePcqePXu46aabrnhoXeUUFI2PfOQj827fuXMndXV1nDhxgq9+9as8+eSTtLa2znrIFLtGC3R3L87mPd8AQp5pyUs6er1eJiYm8Pl8TE1N4fV6MRgMlJeX8zd/8yRVVVXU1hY/K3oxQ7AM8GeSJJ0WQtiAU0KIXxY++6okSV8qljBf+lIbX/3qJYeVJN2+qAtekuZWv9PpdMTjcaanp4slmkI2m1UWMZafwEtV4C0tLQVzRt5O+tZb+XJ7HR0dCCGUGtWzqaz00Nhop7q6GsjbUz0eD5WVlQuOIi0WC7t27eLpp5/m2WefVWLXi4W88k5XVxdXU+Dl5eVs2bJFMZNkMhlGRkZIJBLKTRIIBOjp6WFychKn08l9992H3W4nFosjJ2sVA/mhI8f5L2TO0Ov1bNq0iQceeIDjx48zPT3N2NgYZrMZq9WqFMSSM0YdDgctLS3s2LFDsd0XexSZX6NRTzab5X//72/z3vc+gd1uVyKmhBCUl5dz4sQJQqEtaDQaRkdH+eIXv8jnPvc5xcS23rDb7dx7773s3buXF154gR/96Ef80R/9EZJUxlqX6k2n03R3dzM9PU02m1UqaKZSKYxGI+FwWDHFmUwmJUGtra2Nb3zDjstlYCXWWb9mL0qSNA6MF96HhRAdFGvoNosXX4RU6nIn0uI7bbY/SK/XK6vlFJvW1laGh4cVG7vdbl/yzTB7Cmu1WguFsfJKWZ49yMpO5tlnD/Hqq1pKSkRh9GUglaormHXEAiMKgSTpyGZdBIO/RyaTwe9fmt1+PkZHRwkEAkpUyTe+8U3CYZ+yELFcayOZTPL9739fqaFuNpupqqpCkiQuXrxIb28voVCIQCDA6OgosViM1157jYqKCkZGbgK2FE1m+YFRXV19VSepXKisra2NhoYGxVEsR3PI2bhWq1VZ6Fav1y8YiVMMZtfxbm5u5pvf/Cbvec978Hg8hEIhpf6NfG3W1DRw6NAh3njjDb7+9a/zoQ99iK1bt65o1uVSkFPuHQ4HDz30EMlkkv7+fnw+qKurWBUZ5OticnKS7u5upfyCyWRieHhYmR1GIhHi8bhSvuLgwYO43W7MZjMGgwG9Xo9er8dsNislnVciduC6NI8QogHYDZwADgJPCSE+CJwkP0oPLFWQYq5oIocOFtu7LoRQIlLkamrFipDQaDRKERw5ZFKOM5/NI484uJQvJAqvxWTPyYsnXBoGFKFUDIBiIpiezsu/a9cuMpmoYiaRS8fKJhI5yzQez0fThEIh3n77bSA/w8nlcpSXl+N2u5V6E6WlxZ3fazQanE4nmzZtumYUkRzZIdemkX0rsxf2kP0iqxkGJ4SGlpatDA4OMDQ0RDgcJhaLKY78yspKTCaTUqa3rKyMN954gzfffJOpqSm2bNlCbW3tikZ/nDsHn/nM9f5KC+TjwYeHs3R0WJhltSo66XQav9/P2NgYPp9PWVxZNoVEIhHFBCY/uMvKynA4HGzdulUJsDCZTOj1erRa7ZyIn5W8JBatwIUQJcCzwKclSQoJIb4BfJG8cfKLwJeBKwxcQoiPAR8D5tgOVxI5MkOOZik2cgx4JpO5wsRRDGZmgmQyGbRa7RWjuMceg0cfLfohl0VVVRVVVVUMDeUv1oMHD84xaeVyOZLJJOl0Wsm0DQQC+Hw+wuEwTqeTZDKJwWBAq9ViMBior6+nrq5OqfRW7NOs0Wior6+nqqpqUQpMHh2azeYlJd+sBJIkaG+vYmZmP93dk+j1aUwmO6Ojzbz8MkApMzPg9Rro6rKQydSQTBo5cqQdh2OG1tYILS05pa/SaXjzzbwzsxhs3Qo9PbDAkqiLpJZt22AZSc7zkstl6ezsRghBIpFgeHiYgYEBJiYmGB8fL4Qnm0ilUkqkklwozuFwYLFY8Hg87Fqt5ecXYFEKXAihJ6+8/68kSf8PQJKkyVmf/y/ghfl+K0nSM8AzAHv37l2Vsj8VFRVUVKzclKupqYlUKkU8HldqlBSTVCqfCr+WK5MsFUmC6el8avklNOQXY84rPrPZidm8iYIZ/6oUKvZShJD+OWi12jW/+ZaDVpt3xP3BHwBsL7xk9vGjH+XfhcNw/jwcOSLIL4pxe+EFP/+5nJKfI5fLEo3qePrpDDod3HWXhuWGmj71VP61Hkml0nzrW99S/BdyyLHNZsNkMmE2m6muri4Up3Jx++23r8i9vlwWE4UigH8COiRJ+sqs7VUF+zjAfwDOr4yI65PF1I1eKg0N9ZSU2BRH5UZCkliUYl4KG1jfFp0dO8Dnu/b3Hnwwf97++q+v/Gx2QbahoWHe9a59/Nf/eoy77tIUoplWZ8a8Fmi1Glpbt2E2m5SIMqPRSE1NDQ0NDej1+gWTu9YTixmBHwQ+ALQLIc4Utv134D8KIW4mb0IZBD6+AvKtW1bS1vmpTx1CiFzBxnppe5Eq5K4YNTUwOXnt7y2VdRg4saYs9hL82tfgO9+Zdw9IkglJqiKb9RCNarntttvYv3/+wl83EomEns985gOFKKH8NrkUwewY/2JEvwSW7Bm8NouJQjnK/K1YVsy3ypXo9fDznwMsbJNdgwVgFo1WCytouVJZAl/4AkxdmfNTQL6ttcjmkt27DdzoGe1bt8Lzzwtkk95qUMwgjdmI1VxRe+/evdLJkydX7XgqKioqNwJCiFOSJF0xfFvfBh4VFRUVlQVRFbiKiorKBmVVTShCiCkgCizCf35DUMZvT1tBbe+Nzm9Te9dbW+slSbqiEtaqKnAAIcTJ+Ww5NyK/TW0Ftb03Or9N7d0obVVNKCoqKiobFFWBq6ioqGxQ1kKBP7MGx1wrfpvaCmp7b3R+m9q7Idq66jZwFRUVFZXioJpQVFRUVDYoq6bAhRDvFkJ0CSF6hRCfXa3jriZCiEEhRLsQ4owQ4mRhW6kQ4pdCiJ7C31VYuGplEEJ8WwjhFUKcn7Vt3vaJPP9Q6O9zQog9ayf50ligvV8QQowW+viMEOLBWZ/9eaG9XUKId62N1EtDCFErhHhVCHFBCPGOEOKPC9tvyP69Sns3Vv/Kq4mv5It8oYU+YDP5Qh9ngW2rcezVfJEv6lV22ba/BT5beP9Z4G/WWs5ltO8OYA9w/lrtAx4EfkG+4MYB4MRay1+k9n4B+Mw8391WuK6NQGPheteudRuuo61VwJ7CexvQXWjTDdm/V2nvhurf1RqB3wr0SpLUL0lSCvgXYJ0tS7BiPAp8r/D+e8BjayfK8pAk6dfA5QuNLtS+R4HvS3mOA04hRNWqCFokFmjvQjwK/IskSUlJkgaAXvLX/YZAkqRxSZJOF96HAXnpxBuyf6/S3oVYl/27Wgq8Bhie9f8IK7Cu5jpAAl4WQpwqrEQE4JEu1U2fADzz/3TDslD7buQ+f6pgNvj2LJPYDdPey5ZOvOH797L2wgbqX9WJWVwOSZK0B3gA+M9CiDtmfyjl52I3bNjPjd6+At8AmoCbyS/2/eU1labIXL504uzPbsT+nae9G6p/V0uBjwK1s/7fVNh2QyFJ0mjhrxf4Kfkp1qQ8tSz89a6dhCvCQu27IftckqRJSZKykiTlgP/FpWn0hm/vfEsncgP370JLRW6k/l0tBf4W0CyEaBRCGIAngedW6dirghDCKoSwye+B+8kvM/cc8KHC1z4E/HxtJFwxFmrfc8AHC9EKB4CZWVPxDctldt7ZSwk+BzwphDAKIRqBZuDN1ZZvqSy0dCI3aP8u1N4N17+r6PV9kLyntw/4H2vtvV2B9m0m76U+C7wjtxFwA0eAHuDfgdK1lnUZbfxn8tPKNHkb4H9aqH3koxP+Z6G/24G9ay1/kdr7fwrtOUf+pq6a9f3/UWhvF/DAWst/nW09RN48cg44U3g9eKP271Xau6H6V83EVFFRUdmgqE5MFRUVlQ2KqsBVVFRUNiiqAldRUVHZoKgKXEVFRWWDoipwFRUVlQ2KqsBVVFRUNiiqAldRUVHZoKgKXEVFRWWD8v8BPrZmz42Tv6AAAAAASUVORK5CYII=\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 寻找边缘，返回边框的左上角和右下角（利用cv2.findContours）\n",
    "def findBorderContours(path, maxArea=55):\n",
    "    img = cv2.imread(path, cv2.IMREAD_GRAYSCALE)\n",
    "    img = accessBinary(img)\n",
    "    \n",
    "    contours, _ = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)\n",
    "    borders = []\n",
    "    for contour in contours:\n",
    "        # 将边缘拟合成一个边框\n",
    "        x, y, w, h = cv2.boundingRect(contour)\n",
    "        if w*h > maxArea:\n",
    "            border = [(x, y), (x+w, y+h)]\n",
    "            borders.append(border)\n",
    "    return borders\n",
    "    \n",
    "path = './data/HandWrite/HW_Chinese/test_data/0.png'\n",
    "borders = findBorderContours(path)\n",
    "print(borders)\n",
    "showResults(path, borders)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "id": "53e302c8",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(32, 280, 3)\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "def extractPeek(array_vals, min_vals=20, min_rect=20):\n",
    "    extrackPoints = []\n",
    "    startPoint = None\n",
    "    endPoint = None\n",
    "    for i, point in enumerate(array_vals):\n",
    "        if point > min_vals and startPoint == None:\n",
    "            startPoint = i\n",
    "        elif point < min_vals and startPoint != None:\n",
    "            endPoint = i\n",
    "\n",
    "        if startPoint != None and endPoint != None:\n",
    "            extrackPoints.append((startPoint, endPoint))\n",
    "            startPoint = None\n",
    "            endPoint = None\n",
    "\n",
    "    # 剔除一些噪点\n",
    "    for point in extrackPoints:\n",
    "        if point[1] - point[0] < min_rect:\n",
    "            extrackPoints.remove(point)\n",
    "    return extrackPoints\n",
    "\n",
    "# 寻找边缘，返回边框的左上角和右下角（利用直方图寻找边缘算法（需行对齐））\n",
    "def findBorderHistogram(path):\n",
    "    borders = []\n",
    "    img = cv2.imread(path, cv2.IMREAD_GRAYSCALE)\n",
    "    img = accessBinary(img)\n",
    "    # 行扫描\n",
    "    hori_vals = np.sum(img, axis=1)\n",
    "    hori_points = extractPeek(hori_vals)\n",
    "    # 根据每一行来扫描列\n",
    "    for hori_point in hori_points:\n",
    "        extractImg = img[hori_point[0]:hori_point[1], :]\n",
    "        vec_vals = np.sum(extractImg, axis=0)\n",
    "        vec_points = extractPeek(vec_vals, min_rect=0)\n",
    "        for vect_point in vec_points:\n",
    "            border = [(vect_point[0], hori_point[0]), (vect_point[1], hori_point[1])]\n",
    "            borders.append(border)\n",
    "    return borders\n",
    "    \n",
    "path = './data/HandWrite/HW_Chinese/test_data/0.png'\n",
    "borders = findBorderHistogram(path)\n",
    "showResults(path, borders)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "id": "486011f2",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(32, 280, 3)\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[  765  1785  3570  4335  9945 11985 19125 18360 13770 15300 19125 18615\n",
      " 18615 15045 15555 14025 12750 12750 16575 17340 18870 19890 19380 19380\n",
      " 20910 18870 22950 22185 23205 24225 26010 23205 22185 22950 22695 24480\n",
      " 25755 27030 23205 22695 24990 26265 27285 27795 29325 27285 24990 26520\n",
      " 24225 25245 18615 16320 11985 11730  6375  4845     0     0     0     0\n",
      "     0     0     0     0]\n",
      "1785\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[(12, 48), (70, 97), (114, 166), (198, 245), (268, 328), (350, 394), (423, 455), (486, 536)]]\n",
      "[[(12, 48), (70, 97), (114, 166), (198, 245), (268, 328), (350, 394), (423, 455), (486, 536)]]\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "公司拟逾亿投资三\n",
      "test acc: 1.0\n"
     ]
    }
   ],
   "source": [
    "import cv2\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "import os\n",
    " \n",
    "#base_dir = \"/root/workspace/deep_ocr\"\n",
    "#path_test_image = \"test_data.png\"\n",
    "def pepper(img, n):\n",
    "    for k in range(n):\n",
    "        i = int(np.random.random() * img.shape[1])\n",
    "        j = int(np.random.random() * img.shape[0])\n",
    "        if img.ndim == 2:\n",
    "            img[j, i] == 0\n",
    "        elif img.ndim == 3:\n",
    "            img[j,i,0]= 0    \n",
    "            img[j,i,1]= 0    \n",
    "            img[j,i,2]= 0\n",
    "    return img \n",
    "\n",
    "path_test_image = './data/HandWrite/HW_Chinese/test_data/0.png'\n",
    "image_color = cv2.imread(path_test_image)\n",
    "print(image_color.shape)\n",
    "new_shape = (image_color.shape[1] * 2, image_color.shape[0] * 2)\n",
    "image_color = cv2.resize(image_color, new_shape)\n",
    "#image_color = cv2.resize(image_color, (284,216))\n",
    "image = cv2.cvtColor(image_color, cv2.COLOR_BGR2GRAY)\n",
    "#image=np.rot90(image)\n",
    "#erzhihua\n",
    "adaptive_threshold = cv2.adaptiveThreshold(\n",
    "    image,\n",
    "    255,\n",
    "    cv2.ADAPTIVE_THRESH_GAUSSIAN_C,\\\n",
    "    cv2.THRESH_BINARY_INV, 11, 2)\n",
    "adaptive_threshold = pepper(adaptive_threshold, 500)\n",
    "\n",
    "adaptive_threshold1=cv2.medianBlur(adaptive_threshold,3)\n",
    "adaptive_threshold2=cv2.medianBlur(adaptive_threshold,5)\n",
    "\n",
    "#adaptive_threshold3=cv2.medianBlur(adaptive_threshold,7)\n",
    "adaptive_threshold3=adaptive_threshold\n",
    "plt.imshow(adaptive_threshold3)\n",
    "plt.show()\n",
    "#cv2.imshow('yuan1', adaptive_threshold3)\n",
    "#\n",
    "#cv2.imshow('Media3', adaptive_threshold1)\n",
    "#cv2.imshow('media5', adaptive_threshold2)\n",
    "#cv2.imshow('media7', adaptive_threshold3)\n",
    "#\n",
    "#\n",
    "#cv2.waitKey(0)\n",
    "\n",
    "\n",
    "horizontal_sum = np.sum(adaptive_threshold3, axis=1)\n",
    " \n",
    "#plt.plot(horizontal_sum, range(horizontal_sum.shape[0]))\n",
    "#plt.gca().invert_yaxis()\n",
    "#plt.show()\n",
    "print(horizontal_sum)\n",
    "print(horizontal_sum[1])\n",
    "def extract_peek_ranges_from_array(array_vals, minimun_val=230, minimun_range=2):\n",
    "    start_i = None\n",
    "    end_i = None\n",
    "    peek_ranges = []\n",
    "    for i, val in enumerate(array_vals):\n",
    "#        print(\"val\")\n",
    "#        print(val)\n",
    "#        print(\"***************************i*****************************8\")\n",
    "#        print(i)\n",
    "        if val > minimun_val and start_i is None:\n",
    "            start_i = i\n",
    "        elif val > minimun_val and start_i is not None:\n",
    "            pass\n",
    "        elif val < minimun_val and start_i is not None:\n",
    "            end_i = i\n",
    "            if end_i - start_i >= minimun_range:\n",
    "                peek_ranges.append((start_i, end_i))\n",
    "            start_i = None\n",
    "            end_i = None\n",
    "        elif val < minimun_val and start_i is None:\n",
    "            pass\n",
    "        else:\n",
    "            raise ValueError(\"cannot parse this case...\")\n",
    "    return peek_ranges\n",
    "\n",
    "peek_ranges = extract_peek_ranges_from_array(horizontal_sum)\n",
    "\n",
    "line_seg_adaptive_threshold = np.copy(adaptive_threshold3)\n",
    "for i, peek_range in enumerate(peek_ranges):\n",
    "    x = 0\n",
    "    y = peek_range[0]\n",
    "    w = line_seg_adaptive_threshold.shape[1]\n",
    "    h = peek_range[1] - y\n",
    "    pt1 = (x, y)\n",
    "    pt2 = (x + w, y + h)\n",
    "    cv2.rectangle(line_seg_adaptive_threshold, pt1, pt2, 255)   #huaxianhanshu(cv2.rectangle)\n",
    "#cv2.imshow('line image2', line_seg_adaptive_threshold)\n",
    "plt.imshow(line_seg_adaptive_threshold)\n",
    "plt.show()\n",
    "\n",
    "vertical_peek_ranges2d = []\n",
    "for peek_range in peek_ranges:\n",
    "    start_y = peek_range[0]\n",
    "    end_y = peek_range[1]\n",
    "    line_img = adaptive_threshold[start_y:end_y, :]\n",
    "    vertical_sum = np.sum(line_img, axis=0)\n",
    "    vertical_peek_ranges = extract_peek_ranges_from_array(\n",
    "        vertical_sum,\n",
    "        minimun_val=40,\n",
    "        minimun_range=1)\n",
    "    vertical_peek_ranges2d.append(vertical_peek_ranges)\n",
    "print(vertical_peek_ranges2d)\n",
    "tmp=[vertical_peek_ranges2d[0][0]]\n",
    "for i in range(1,len(vertical_peek_ranges2d[0])):\n",
    "    if abs(vertical_peek_ranges2d[0][i][0]-vertical_peek_ranges2d[0][i-1][1])>5:\n",
    "        tmp.append(vertical_peek_ranges2d[0][i])\n",
    "    else:\n",
    "        tmp[-1]=(tmp[-1][0],vertical_peek_ranges2d[0][i][1])\n",
    "vertical_peek_ranges2d=[tmp]\n",
    "    \n",
    "print(vertical_peek_ranges2d)\n",
    "## Draw\n",
    "color = (0, 0, 255)\n",
    "for i, peek_range in enumerate(peek_ranges):\n",
    "    for vertical_range in vertical_peek_ranges2d[i]:\n",
    "        x = vertical_range[0]\n",
    "        y = peek_range[0]\n",
    "        w = vertical_range[1] - x\n",
    "        h = peek_range[1] - y\n",
    "        pt1 = (x, y)\n",
    "        pt2 = (x + w, y + h)\n",
    "        cv2.rectangle(image_color, pt1, pt2, color)\n",
    "plt.imshow(image_color)\n",
    "plt.show()\n",
    "\n",
    "\n",
    "# def median_split_ranges(peek_ranges):\n",
    "#     new_peek_ranges = []\n",
    "#     widthes = []\n",
    "#     for peek_range in peek_ranges:\n",
    "#         w = peek_range[1] - peek_range[0] + 1\n",
    "#         widthes.append(w)\n",
    "#     widthes = np.asarray(widthes)\n",
    "#     median_w = np.median(widthes)\n",
    "#     for i, peek_range in enumerate(peek_ranges):\n",
    "#         num_char = int(round(widthes[i]/median_w, 0))\n",
    "#         if num_char > 1:\n",
    "#             char_w = float(widthes[i] / num_char)\n",
    "#             for i in range(num_char):\n",
    "#                 start_point = peek_range[0] + int(i * char_w)\n",
    "#                 end_point = peek_range[0] + int((i + 1) * char_w)\n",
    "#                 new_peek_ranges.append((start_point, end_point))\n",
    "#         else:\n",
    "#             new_peek_ranges.append(peek_range)\n",
    "#     return new_peek_ranges\n",
    "\n",
    "\n",
    "# vertical_peek_ranges2d = []\n",
    "# for peek_range in peek_ranges:\n",
    "#     start_y = peek_range[0]\n",
    "#     end_y = peek_range[1]\n",
    "#     line_img = adaptive_threshold[start_y:end_y, :]\n",
    "#     vertical_sum = np.sum(line_img, axis=0)\n",
    "#     vertical_peek_ranges = extract_peek_ranges_from_array(\n",
    "#         vertical_sum,\n",
    "#         minimun_val=40,\n",
    "#         minimun_range=1)\n",
    "#     vertical_peek_ranges = median_split_ranges(vertical_peek_ranges)\n",
    "#     vertical_peek_ranges2d.append(vertical_peek_ranges)\n",
    "\n",
    "# ## Draw\n",
    "# color = (0, 0, 255)\n",
    "# for i, peek_range in enumerate(peek_ranges):\n",
    "#     for vertical_range in vertical_peek_ranges2d[i]:\n",
    "#         x = vertical_range[0]\n",
    "#         y = peek_range[0]\n",
    "#         w = vertical_range[1] - x\n",
    "#         h = peek_range[1] - y\n",
    "#         pt1 = (x, y)\n",
    "#         pt2 = (x + w, y + h)\n",
    "#         cv2.rectangle(image_color, pt1, pt2, color)\n",
    "# plt.imshow(image_color)\n",
    "# plt.show()\n",
    "test(new_model)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3e5b139c",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.7"
  },
  "rise": {
   "autolaunch": true,
   "enable_chalkboard": true
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {
    "height": "calc(100% - 180px)",
    "left": "10px",
    "top": "150px",
    "width": "165px"
   },
   "toc_section_display": true,
   "toc_window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
